"《算法导论》之‘线性表’":基于动态分配的数组的顺序表

时间:2023-03-08 18:45:11
"《算法导论》之‘线性表’":基于动态分配的数组的顺序表

  我们利用静态分配的数组来实现的顺序表的局限还是挺大的,主要在于它的容量是预先定好的,用户不能根据自己的需要来改变。如果为了后续用户能够自己调整顺序表的大小,动态地分配数组空间还是很有必要的。基于动态分配的数组的顺序表绝大部分跟基于静态分配的数组的顺序表是一样的,只需在后者程序上改动一小部分即可。

  第一,我们不需定义一个容量常量CAPACITY,而是定义一个私有变量myCapacity。

  第二,类的构造函数需要改进一下。我们需要类在被实例化时自动申请内存,即需添加下边程序:

ElementType * seqList = new ElementType(myCapacity);
assert(seqList != NULL);

  第三,类的析构函数需要添加下边一句:

delete [] seqList;

  上面三点说的还有所欠缺。Larry Nyhoff在《数据结构与算法分析》第253页中提到设计类时要记住的一条规则:

  如果类在运行时使用new分配内存,则它应该提供:

  • 把动态分配的内存还给堆的析构函数。
  • 编译器用来创建不同副本的复制构造函数。
  • 程序员用来创建不同副本的赋值运算符。

  基于动态分配的数组的顺序表设计的类如下:

 // seqlist.h
#ifndef SEQLIST
#define SEQLIST #include <iostream>
#include <cassert>
#include <algorithm> using namespace std; typedef int ElementType; class SeqList
{
public:
SeqList(const int maxsize = );
virtual ~SeqList();
SeqList(const SeqList& origList);                // 拷贝构造函数,记得防止浅拷贝
const SeqList& operator=(const SeqList& rightHandSide); // 重载赋值运算符,记得防止浅拷贝
bool empty() const;
void clear();
bool insert(const int pos, const ElementType val);
bool erase(const int pos);
void display() const;
bool setSeqList(const ElementType *tmpList, const int len);
int getLenOfList() const;
ElementType getItem(const int pos);
ElementType * getSeqList();                   // 保留,不推荐使用,因为在使用过程中无法进行越界检查 private:
int myCapacity;                          // 自定义顺序表容量
int lenOfList;                           // 顺序表长度
ElementType * seqList; }; #endif

  实现程序为:

 // seqlist.cpp
#include <iostream>
#include <cassert>
#include "seqlist.h" using namespace std; SeqList::SeqList(const int maxsize)
{
// initialization
lenOfList = ;
myCapacity = maxsize;
seqList = new ElementType[myCapacity];
// assert(seqList != NULL);
if (seqList == NULL)
{
cerr << "Inadequate memory to allocate stack." << endl;
throw bad_alloc();
}
} SeqList::~SeqList()
{
delete[] seqList;
} SeqList::SeqList(const SeqList& origList)
{
myCapacity = origList.myCapacity;
lenOfList = origList.lenOfList;
seqList = new ElementType[myCapacity];
// assert(seqList != NULL);
if (seqList == NULL)
{
cerr << "Inadequate memory to allocate stack." << endl;
throw bad_alloc();
}
else
{
for (int i = ; i < lenOfList; i++)
{
seqList[i] = origList.seqList[i];
}
}
} const SeqList& SeqList::operator=(const SeqList& rightHandSide)
{
// 确保不是自我赋值
if (this != &rightHandSide)
{
// 如果需要,分配一个新数组
if (myCapacity != rightHandSide.myCapacity)
{
delete[] seqList;
myCapacity = rightHandSide.myCapacity;
seqList = new ElementType[myCapacity];
// assert(seqList != NULL);
if (seqList == NULL)
{
cerr << "Inadequate memory to allocate stack." << endl;
throw bad_alloc();
}
} lenOfList = rightHandSide.lenOfList;
for (int i = ; i < lenOfList; i++)
{
seqList[i] = rightHandSide.seqList[i];
}
}
return *this;
} bool SeqList::empty() const
{
return lenOfList == ;
} void SeqList::clear()
{
lenOfList = ;
fill(seqList, seqList + myCapacity - , );
} bool SeqList::insert(const int pos, const ElementType val)
{
bool success = false;
// assert(lenOfList != CAPACITY); // 这里的assert分成两行写,是为了方便定位错误发生的地方
// assert(0 <= pos <= lenOfList);
if (lenOfList == myCapacity)
{
cerr << "No space for insertion!" << endl;
}
else if (pos < || pos > lenOfList)
{
cerr << "The position " << pos <<
" you want to insert is less than zero or exceeds the length of the list!" << endl;
throw out_of_range("throw out_of_range"); // 抛出一个越界异常
}
else
{
int tmpCount = lenOfList - pos;
for (int i = ; i < tmpCount; i++)
{
seqList[lenOfList - i] = seqList[lenOfList - i - ];
}
seqList[pos] = val;
lenOfList++;
success = true;
}
return success;
} bool SeqList::erase(const int pos)
{
bool success = false;
// assert(lenOfList != 0);
// assert(0 <= pos <= lenOfList);
if (lenOfList == )
{
cerr << "There is no elements in the list!" << endl;
}
else if (pos < || pos > lenOfList)
{
cerr << "The position " << pos <<
" you want to erase is less than zero or exceeds the length of the list!" << endl;
throw out_of_range("throw out_of_range"); // 抛出一个越界异常
}
else
{
int tmp = lenOfList - pos;
for (int i = ; i < tmp - ; i++)
{
seqList[pos + i] = seqList[pos + i + ];
}
seqList[lenOfList - ] = ;
lenOfList--;
success = true;
}
return success;
} void SeqList::display() const
{
cout << "***Start Displaying***" << endl;
if (lenOfList == )
{
cerr << "There is no element in the the list!" << endl;
}
else
{
for (int i = ; i < lenOfList; i++)
{
cout << i << " : " << seqList[i] << endl;
}
cout << "***End Displaying***" << endl;
}
} bool SeqList::setSeqList(const ElementType *tmpList, const int len)
{
// assert(len <= CAPACITY);
bool success = false;
if (len <= myCapacity)
{
for (int i = ; i < len; i++)
{
seqList[i] = *(tmpList++);
}
lenOfList = len;
success = true;
}
else
{
cerr << "The length of the array you set exceeds the CAPACITY." << endl;
throw out_of_range("throw out_of_range"); // 抛出一个越界异常
}
return success;
} int SeqList::getLenOfList() const
{
return lenOfList;
} ElementType SeqList::getItem(const int pos)
{
// assert(0 <= pos <= lenOfList);
if (pos < || pos > lenOfList)
{
cerr << "The item at " << pos << " you want to get does not exist!" << endl;
throw out_of_range("throw out_of_range"); // 抛出一个越界异常
}
else
{
return seqList[pos];
}
} ElementType * SeqList::getSeqList()
{
return seqList;
}

seqlist.cpp

  Boost单元测试程序为:

 // BoostUnitTest.cpp
#define BOOST_TEST_MODULE ArrayList_Test_Module #include "stdafx.h"
#include "D:\VSProject\Algorithm\List\SeqList\SeqList_BsedOnDynamicArray\SeqList\seqlist.h" struct ArrayList_Fixture
{
ArrayList_Fixture()
{
BOOST_TEST_MESSAGE("Setup fixture");
testArrayList = new SeqList();
}
~ArrayList_Fixture()
{
BOOST_TEST_MESSAGE("Teardown fixture");
delete testArrayList;
} SeqList * testArrayList;
}; // BOOST_AUTO_TEST_SUITE(ArrayList_Test_Suite)
BOOST_FIXTURE_TEST_SUITE(ArrayList_Test_Suite, ArrayList_Fixture) BOOST_AUTO_TEST_CASE(ArrayList_Abnormal_Test)
{
// Set values to the array list
int testArray[] = { , , , , }; // 5 个元素
int testLenOfList = sizeof(testArray) / sizeof(int);
testArrayList->setSeqList(testArray, testLenOfList);
// BOOST_REQUIRE_THROW(testArrayList->setArrayList(testArray, testLenOfList), out_of_range); // Method getItem-----------------------------------------------
// If the position of the item you want to get is less than zero
BOOST_REQUIRE_THROW(testArrayList->getItem(-), out_of_range);
// If the position of the item you want to get is larger than the length of the list
BOOST_REQUIRE_THROW(testArrayList->getItem(), out_of_range); // Method insert-------------------------------------------------
// If the inserting position is less than zero
BOOST_REQUIRE_THROW(testArrayList->insert(-, ), out_of_range);
BOOST_REQUIRE(testArrayList->getLenOfList() == testLenOfList); // If the inserting position is larger than the length of the list
BOOST_REQUIRE_THROW(testArrayList->insert(, ), out_of_range);
BOOST_REQUIRE(testArrayList->getLenOfList() == testLenOfList); // Method erase-------------------------------------------------
// If the erasing position is less than zero
BOOST_REQUIRE_THROW(testArrayList->erase(-), out_of_range);
BOOST_REQUIRE(testArrayList->getLenOfList() == testLenOfList); // If the erasing position is larger than the length of the list
BOOST_REQUIRE_THROW(testArrayList->erase(), out_of_range);
BOOST_REQUIRE(testArrayList->getLenOfList() == testLenOfList); } BOOST_AUTO_TEST_CASE(ArrayList_Normal_Test)
{
bool expected;
bool actual;
// Method empty-------------------------------------------------
expected = true;
actual = testArrayList->empty();
BOOST_REQUIRE(expected == actual); // Set values to the array list
int testArray[] = { , , , , }; // 5 个元素
int testLenOfList = sizeof(testArray) / sizeof(int);
testArrayList->setSeqList(testArray, testLenOfList);
// BOOST_REQUIRE_THROW(testArrayList->setArrayList(testArray, testLenOfList), out_of_range); // Method getItem-----------------------------------------------
BOOST_REQUIRE(testArrayList->getItem() == testArray[]); // Method empty-------------------------------------------------
expected = false;
actual = testArrayList->empty();
BOOST_REQUIRE(expected == actual); // Method insert-------------------------------------------------
expected = true;
actual = testArrayList->insert(, );
BOOST_REQUIRE(expected == actual);
BOOST_REQUIRE(testArrayList->getLenOfList() == testLenOfList + );
BOOST_REQUIRE(testArrayList->getItem() == ); // Method erase-------------------------------------------------
expected = true;
actual = testArrayList->erase();
BOOST_REQUIRE(expected, actual);
BOOST_REQUIRE(testArrayList->getLenOfList() == testLenOfList);
BOOST_REQUIRE(testArrayList->getItem() == testArray[]); } BOOST_AUTO_TEST_CASE(ArrayList_CopyConstructor_Test)
{
bool expected;
bool actual;
// Set values to the array list
int testArray[] = { , , , , }; // 5 个元素
int testLenOfList = sizeof(testArray) / sizeof(int);
testArrayList->setSeqList(testArray, testLenOfList);
// BOOST_REQUIRE_THROW(testArrayList->setArrayList(testArray, testLenOfList), out_of_range); // Copy constructor
//SeqList * copySeqList(testArrayList); // 极容易写成这样子。错误。
// 需要给copySeqList分配内存
SeqList * copySeqList = new SeqList(*testArrayList); // Method getItem-----------------------------------------------
BOOST_REQUIRE(copySeqList->getItem() == testArray[]); // Method empty-------------------------------------------------
expected = false;
actual = copySeqList->empty();
BOOST_REQUIRE(expected == actual); // Method insert-------------------------------------------------
expected = true;
actual = copySeqList->insert(, );
BOOST_REQUIRE(expected == actual);
BOOST_REQUIRE(copySeqList->getLenOfList() == testLenOfList + );
BOOST_REQUIRE(copySeqList->getItem() == ); // Method erase-------------------------------------------------
expected = true;
actual = copySeqList->erase();
BOOST_REQUIRE(expected, actual);
BOOST_REQUIRE(copySeqList->getLenOfList() == testLenOfList);
BOOST_REQUIRE(copySeqList->getItem() == testArray[]);
} BOOST_AUTO_TEST_CASE(ArrayList_EqualOperator_Test)
{
bool expected;
bool actual;
// Set values to the array list
int testArray[] = { , , , , }; // 5 个元素
int testLenOfList = sizeof(testArray) / sizeof(int);
testArrayList->setSeqList(testArray, testLenOfList);
// BOOST_REQUIRE_THROW(testArrayList->setArrayList(testArray, testLenOfList), out_of_range); // Copy constructor
SeqList * copySeqList = new SeqList();
// copySeqList = testArrayList; // 极易犯的一个低级错误
*copySeqList = *testArrayList; // Method getItem-----------------------------------------------
BOOST_REQUIRE(copySeqList->getItem() == testArray[]); // Method empty-------------------------------------------------
expected = false;
actual = copySeqList->empty();
BOOST_REQUIRE(expected == actual); // Method insert-------------------------------------------------
expected = true;
actual = copySeqList->insert(, );
BOOST_REQUIRE(expected == actual);
BOOST_REQUIRE(copySeqList->getLenOfList() == testLenOfList + );
BOOST_REQUIRE(copySeqList->getItem() == ); // Method erase-------------------------------------------------
expected = true;
actual = copySeqList->erase();
BOOST_REQUIRE(expected, actual);
BOOST_REQUIRE(copySeqList->getLenOfList() == testLenOfList);
BOOST_REQUIRE(copySeqList->getItem() == testArray[]);
} BOOST_AUTO_TEST_SUITE_END();

BoostUnitTest.cpp

  本篇博文的代码均托管到Taocode : http://code.taobao.org/p/datastructureandalgorithm/src/.