在C或C++里,我们已经学会了如何实现一个静态顺序表了,那为何还要引入模版类来实现静态顺序表呢?首先,我们看,在未引入模版前,我们在C++里是这样定义一个静态顺序表的:
typedef int DataType; //此时我定义的是int型 class SeqList { DataType* _array; size_t _size; size_t _capacity; }
我们若要定义char型或者其他类型的,可以采用typedef了,这就是使用typedef的优势之处。另外,还利于统一管理程序代码,增加代码的可维护性。
可是,有时候我们会不会遇到这样的问题呢:
void Test() { SeqList s1; //此时s1我想定义成为char型 SeqList s2; //此时s2我想定义成为非char型 }
这时候,若我们使用typedef换来换去的,难免使得代码混乱或者出错。若是再定义一个类来实现另外一个类型的静态顺序表,这时候代码两处相似度极高,也不利于维护。因此,我们引入模板,模板类的实例化可以轻而易举地解决好这个问题。
代码如下:
#include<iostream> using namespace std; #include<string> #include<assert.h> template<class T> class SeqList { private: T* _array; size_t _size; size_t _capacity; public: SeqList() :_array(NULL) , _size(0) , _capacity(0) {} SeqList(const SeqList<T>& s) { _array = new T[s._size]; for (size_t i = 0; i < s._size; i++) { _array[i] = s._array[i]; } _size = s._size; _capacity = s._size; } SeqList<T>& operator=(SeqList<T> s) { if (&s != this) { swap(_array, s._array); swap(_size, s._size); swap(_capacity, s._capacity); } return *this; } ~SeqList() { if (_array) { delete[] _array; } } //扩容 void _CheckCapacity(size_t n) { if (n > _capacity) { _capacity = n > 2 * _capacity + 3 ? n : 2 * _capacity + 3; /*_array = (T*)realloc(_array, sizeof(T)* _capacity);*/ //不可行!realloc对于自定义类型未调用构造函数初始化对象,随机值会崩溃。 T* tmp = new T[_capacity]; if (_array) { /*memcpy(tmp, _array, sizeof(T)* _size);*/ //不可行!对于长字符串重新开辟空间拷贝析构两次崩溃 for (size_t i = 0; i < _size; i++) { tmp[i] = _array[i]; } } delete[] _array; _array = tmp; } } //打印 void PrintSeqList() { for (size_t i = 0; i < _size; i++) { cout << _array[i] << " "; } cout << endl; } //尾插 void PushBack(const T& x) { _CheckCapacity(_size + 1); _array[_size++] = x; } //operator[] T& operator[](size_t index) { assert(index < _size); return _array[index]; } //请求空间 void Reserve(size_t n) { _CheckCapacity(n); } }; void Test() { SeqList<int> s1; s1.PushBack(1); s1.PushBack(2); s1.PushBack(3); s1.PushBack(4); s1.PushBack(5); s1.PrintSeqList(); SeqList<string> s2; s2.PushBack("xxx"); s2.PushBack("xxx"); s2.PushBack("xxx"); s2.PushBack("xxx"); s2.PushBack("xxx"); s2.PrintSeqList(); SeqList<string> s3(s2); s3[0] = "yyy"; s3.PrintSeqList(); } int main() { Test(); system("pause"); return 0; }
在这里,我们关注下reserve()函数,接口实现请求一个容量。我们查看cplusplus.com可以找vector(顺序表)中的reserve(size_t n)。n表示开辟多大的空间。
其他的函数之前的博客实现过,我们这里就不再重复实现了。