最近學習了數據結構,對線性表有了比較深刻的認識,並和c++中容器的實現對照了下,有了點小收獲,記錄下來。。
1,首先線性表有2種存儲結構:順序存儲結構,鏈式存儲結構。(先說順序存儲,之后看鏈表list的時候再說)順序存儲就相當於數組,連續的存儲地址,插入和刪除要移動大量的數據元素,因為地址是連續的,但是隨機訪問能力好,也就是下標訪問元素的能力。
2.對c++中vector類模板的實現,改變了數組固定大小的缺點,可以動態添加或刪除元素改變容器的大小,有很多的函數成員,使用起來也很方便。
其實vector就是可變大小的數組,支持快速隨機訪問,除了尾部之外的地方插入和刪除元素很慢。(因為要保持連續的線性存儲空間)
3.自己寫了一個vector類模板,只是實現了部分功能,一般的大小,插入,刪除,訪問等。。看了primer之后利用allocator類實現了另一個版本。
4.代碼如下Vector.h為頭文件。
/*vector是可變大小的數組,是順序存儲結構,支持快速的隨機訪問,在尾部之外的位置插入和刪除元素很慢*/ #ifndef VECTOR_H #define VECTOR_H #include<cassert> #include<iostream> using namespace std; template<typename T> class Vector { public: enum{ SPARE_CAPACITY = 5 }; typedef T* iterator; typedef const T* const_iterator; //構造函數 explicit Vector(int initsize = 0); //explicit是為了防止讓一個實參的構造函數發生隱式轉換 Vector(int initsize, T value); Vector(iterator b, iterator e); //接受兩個迭代器創建拷貝的構造函數 ,這里的迭代器的創建是指針,見上面 Vector(std::initializer_list<T> l); Vector(const Vector &rhs); Vector<T>& operator=(const Vector & rhs); ~Vector() { delete[] elem;} //常量成員函數,不改變類的成員,this指針為指向常量的常量指針,因為常量對象不能調用非常量數據成員,而非常量對象都可以調用 bool empty()const { return thesize == 0;} int size() const {return thesize;} int capacity() const { return thecapacity; } iterator begin() {return &elem[0];} iterator end() {return &elem[thesize];} const_iterator cbegin()const {return &elem[0];} const_iterator cend() const {return &elem[thesize];} bool operator==(const Vector<T>& rhs); bool operator!=(const Vector<T>& rhs); void reserve(int newcapacity); void resize(int newsize, const T &thevalue); void resize(int newsize); void shrink_to_fit(); T &operator[](int index); const T &operator[](int index) const; T &front(); const T &front() const; T &back(); const T &back() const; void push_back(const T &x); iterator insert(iterator b, const T &value); void pop_back() {thesize--;} iterator erase(iterator b); void clear(); private: T *elem; int thesize; int thecapacity; }; /******************************************構造函數******************************************/ template <typename T> Vector<T>::Vector(int initsize = 0) :thesize(initsize), thecapacity(initsize + SPARE_CAPACITY) { elem = new T[thecapacity]; assert(elem != NULL); //存儲分配失敗則退出; } template<typename T> Vector<T>::Vector(std::initializer_list<T> l) //列表初始化,新標准 { thesize = l.size(); thecapacity = thesize + SPARE_CAPACITY; elem = new T[thecapacity]; assert(elem != NULL); int i = 0; auto beg = l.begin(); while (beg != l.end() && i != thesize) { elem[i] = *beg; ++i; ++beg; } } template <typename T> Vector<T>::Vector(int initsize, T value) :thesize(initsize), thecapacity(initsize + SPARE_CAPACITY) { elem = new T[thecapacity]; assert(elem != NULL); //存儲分配失敗則退出; for (int i = 0; i != thesize; ++i) elem[i] = value; } template <typename T> Vector<T>::Vector(iterator b, iterator e) { thesize = e - b; thecapacity = thesize + SPARE_CAPACITY; elem = new T[thecapacity]; assert(elem != NULL); for (int i = 0; b != e&&i != thesize; ++i) { elem[i] = *b; ++b; } } //拷貝構造函數,接受一個容器為另一個容器的拷貝(深拷貝) template <typename T> Vector<T>::Vector(const Vector &rhs) { thesize = rhs.thesize; thecapacity = rhs.thecapacity; elem = new T[thecapacity]; assert(elem != NULL); for (int i = 0; i != thesize; ++i) elem[i] = rhs.elem[i]; } //賦值運算符 template<typename T> Vector<T>& Vector<T>::operator=(const Vector &rhs) { if (this != &rhs) //防止自賦值 { delete[]elem; thesize = rhs.thesize; thecapacity = rhs.thecapacity; elem = new T[thecapacity]; assert(elem != NULL); for (int i = 0; i != thesize; ++i) elem[i] = rhs.elem[i]; } return *this; } //swap函數的實現,通常比從一個向另一個容器拷貝元素快,只是交換了兩個容器內部的數據結構,元素本身沒有交換。。 //交換的是相同類型的容器。 //assign,賦值函數的實現 /********************************************關系運算符**********************************/ //關系運算符的實現==,!=,> ,>=, <, <= template<typename T> bool Vector<T>::operator==(const Vector<T>& rhs) { if (this->thesize == rhs.thesize) //與容量沒有關系 { int cnt = 0; for (int i = 0; i != thesize; i++) if (this->elem[i] == rhs.elem[i]) ++cnt; if (cnt == thesize) return true; } return false; } template<typename T> bool Vector<T>::operator!=(const Vector<T>& rhs) { return !(*this == rhs); } //分配至少容納newcapacity個的元素空間 template<typename T> void Vector<T>::reserve(int newcapacity) { if (newcapacity <= thecapacity) { if (newcapacity < thecapacity / 2) //當新的容量很小時 { T *newarray = new T[newcapacity]; int newsize = newcapacity > thesize ? thesize : newcapacity; for (int i = 0; i != newsize; ++i) newarray[i] = elem[i]; delete[] elem; elem = newarray; thecapacity = newcapacity; } return; } T *newarray = new T[newcapacity]; for (int i = 0; i != thesize; ++i) newarray[i] = elem[i]; delete[] elem; elem = newarray; thecapacity = newcapacity; } //調整它的大小,若newsize<thesize,多的元素被丟棄,若相反,添加新元素,新添進來的元素初始化為thevalue template<typename T> void Vector<T>::resize(int newsize, const T & thevalue) { if (newsize > thesize) { if (newsize > thecapacity) reserve(newsize * 2 + 1); for (int i = thesize; i != newsize; ++i) //新添進來的元素初始化為thevalue elem[i] = thevalue; } else if (newsize< thesize) { if (newsize<thecapacity / 2) reserve(newsize); } thesize = newsize; } template<typename T> void Vector<T>::resize(int newsize) //調整它的大小,若newsize<thesize,多的元素被丟棄,若相反,添加新元素,進行值初始化 { resize(newsize, T()); } template<typename T> void Vector<T>::shrink_to_fit() //將capacity()減少為與size()相同大小 { reserve(thesize + SPARE_CAPACITY); } /**************************************訪問操作***************************************/ template<typename T> T & Vector<T>::operator[](int index) { if (index < 0 || index >= thesize) { cout << "下標超出范圍" << endl; return; } return elem[index]; } template<typename T> const T &Vector<T>::operator[](int index) const //返回下標不能修改 { if (index < 0 || index >= thesize) { cout << "下標超出范圍" << endl; return; } return elem[index]; } template<typename T> T& Vector<T>::front() { if (!this->empty()) return elem[0]; } template<typename T> const T& Vector<T>::front() const { if (!this->empty()) return elem[0]; } template<typename T> T& Vector<T>::back() { if (!this->empty()) return elem[thesize - 1]; } template<typename T> const T& Vector<T>::back() const { if (!this->empty()) return elem[thesize - 1]; } /******************************************插入操作*************************************/ //向容器插入元素,vector不支持push_front,但insert可以實現插入vector的任何位置,但是注意在vector除尾部之外的任何位置很慢,很耗時。。 template<typename T> void Vector<T>::push_back(const T &x) { if (thesize == thecapacity) reserve(2 * thecapacity); elem[thesize++] = x; } template<typename T> T* Vector<T>::insert(iterator b, const T &value) //返回類型為Vector<T>::iterator則出錯?? { if (b < this->begin() || b> this->end()) //b可以為尾后迭代器 { cout << "超出范圍" << endl; exit(0); } int num = b - elem; if (thesize == thecapacity) { reserve(thesize * 2); b = elem + num; //重新分配內存后原來的指針b失效了,所以此處令b指向新分配的數組中 } for (iterator p = this->end(); p > b; p--) *p = *(p - 1); *b = value; thesize++; return b; } //刪除操作 template<typename T> T* Vector<T>::erase(iterator b) { if (b < this->begin() || b >= this->end()) //確保迭代器在范圍內,否則未定義,b不能為尾后迭代器 { cout << "超出范圍" << endl; exit(0); } iterator q = b + 1; int num = q - elem; iterator p = this->end() - 1; for (; b < p; b++) *b = *(b + 1); thesize--; if (thesize <= thecapacity / 4) //防止刪除后空閑空間太大,浪費空間 { reserve(thesize + SPARE_CAPACITY); iterator q1 = elem + num; //重新進行內存分配后原來的指針q可能失效了 return q1; } return q; } template<typename T> void Vector<T>::clear() { thesize = 0; } #endif
附上測試代碼:
#include <string> #include<iostream> #include"Vector.h" //注意當這里不是標准庫的頭文件,是自己寫的,要用雙引號,整了好久,還以為程序出錯了。。 using namespace std; int main() { Vector<int> v1; Vector<int> v2(5, 9); Vector<int> v3(v2); Vector<int> v4(v2.begin(), v2.end()); if (v1.empty()) cout <<"v1為空,大小為:"<< v1.size() << endl; cout << "向v1插入元素:"; int a; while (cin >> a) v1.push_back(a); if (!v1.empty()) cout << "v1不為空,大小為:" << v1.size() << "容量為:" << v1.capacity() << endl; cout << "元素為:"; for (Vector<int>::iterator iter = v1.begin(); iter != v1.end(); ++iter) cout << *iter << " "; cout << endl; cout << "重新插入后:"; v1.insert(v1.begin() + 1, 4); cout << "此時v1大小為:" << v1.size() << "容量為:" << v1.capacity() << endl; cout << "元素為:"; for (Vector<int>::iterator iter = v1.begin(); iter != v1.end(); ++iter) cout << *iter << " "; cout << endl; cout << "刪除元素后為:"; v1.pop_back(); for (Vector<int>::iterator iter = v1.begin(); iter != v1.end(); ++iter) cout << *iter << " "; cout << endl; cout << "再次刪除元素后為:"; v1.erase(v1.begin() + 2); for (Vector<int>::iterator iter = v1.begin(); iter != v1.end(); ++iter) cout << *iter << " "; cout << endl; cout << "v2元素為:"; for (Vector<int>::iterator iter = v2.begin(); iter != v2.end(); ++iter) cout << *iter << " "; cout << endl; cout << "v3元素為:"; for (Vector<int>::iterator iter = v3.begin(); iter != v3.end(); ++iter) cout << *iter << " "; cout << endl; cout << "v4元素為:"; for (Vector<int>::iterator iter = v4.begin(); iter != v4.end(); ++iter) cout << *iter << " "; cout << endl; if (v1 == v3) cout << "v1與v3相等"; else cout << "v1與v3不相等" << endl; Vector<int> v = { 1, 2, 3, 4, 5 }; Vector<int> v5; v5 = v; cout << "v5元素為:"; for (Vector<int>::iterator iter = v5.begin(); iter != v5.end(); ++iter) cout << *iter << " "; cout << endl; v5.push_back(99); v5.resize(2, 2); cout << "操作后v5元素為:"; for (Vector<int>::iterator iter = v5.begin(); iter != v5.end(); ++iter) cout << *iter << " "; cout << endl; std::cout << v5.capacity() << "\n"; return 0; }
運行結果:

