這個其實是很久之前寫的,最近參加面試,復習C++,感覺不錯,順便翻出來整理了一遍。
使用過容器的都清楚,容器說白了其實就是一個類模板,它可以存放各種類型。而要對容器元素訪問就要通過一個叫
迭代器的東西,迭代器在使用上和指針很相似。因此list容器的實現也主要是對類模板和迭代器的設計,當然也少不了
鏈表操作,因為list容器是通過鏈表來存放數據。
一、節點類
該類主要是存放容器內元素的數據(data)
1 /* 2 *節點類 3 */ 4 template<typename elemType> 5 class Node 6 { 7 private: 8 elemType data; 9 Node *next; 10 public: 11 Node():next(NULL) 12 {} 13 Node(elemType data):data(data),next(NULL) 14 {} 15 //類Iter、Mylist要設為友元 16 friend class Iter<elemType>; 17 friend class Mylist<elemType>; 18 19 };
二、迭代器類
迭代器的實現。看了下面的實現你或許就明白為什么說迭代器和指針很相似,因為它重載了指針的一些基本操作如 ‘*’,'->'等。
記錄一個我當時一個很低級的錯誤:
在實現'->'重載時,我本來是通過間接訪問節點數據:
1 elemType * operator ->()const 2 {//重載迭代器->操作 3 return &(node.getData()); 4 }
但這顯然是不行的,因為getData()返回的是一個臨時變量,對其取到的地址,並非原節點數據的地址。因此要把迭代器類設為節點類的友元類,直接訪問節點數據。
如下:
1 elemType * operator ->()const 2 {//重載迭代器->操作 3 return &(node->data); 4 }
1 /* 2 *迭代器類 3 */ 4 template<typename elemType> 5 class Iter 6 { 7 private: 8 Node<elemType> *node; 9 public: 10 Iter(){} 11 Iter(Node<elemType>* a):node(a){} 12 13 elemType operator *() const 14 {//*重載 15 return (node->data); 16 } 17 elemType * operator ->()const 18 {//重載迭代器->操作 19 return &(node->data); 20 } 21 bool operator !=(Iter<elemType> &a)const 22 {//重載迭代器!=操作 23 return node != a.node; 24 } 25 bool operator == (Iter<elemType> &a)const 26 {//重載迭代器==操作 27 return node == a.node; 28 } 29 Iter<elemType> operator++(int) 30 {//重載迭代器++作 31 Iter<elemType>tmp = *this; 32 this->node = this->node->next; 33 return tmp; 34 } 35 Node<elemType> * getNode(){ return node;} 36 };
三、容器類
在這里實現一些基本的容器操作,如push_front()、push_back()、erase()、sort()等。重點講一下sort()的實現也是花了我最多時間的地方。
本來想用冒泡直接來的,后來發現c++中list容器的sort()函數是通過歸並算法實現的,因此我也采用歸並DIY一個。
冒泡O(N^2),相比於歸並最壞情形運行時間:O(NlogN),當問題規模變大時,冒泡顯然是吃不消的。
首先是遞歸二分鏈表,遞歸到最后會把鏈表分為一個個長度為1的單獨節點,然后再有序地往上歸並這些節點,把長度為1的擴到2,2擴到4,4擴到8……(這
也是分治思想的精髓)。為了提高二分的效率,二分鏈表時使用了兩個步長一快一慢的指針,快指針的遍歷的速度是慢指針的兩倍,這樣當快指針遍歷
到末結點時,慢指針剛好指在了鏈表的中間結點處。
為了對sort()函數的封裝,就要使用函數指針了。容器內定義一個函數指針,測試程序寫好cmp()排序方式函數,通過sort(cmp)調用,初始化容器內的
函數指針,使其指向cmp函數。(如果你沒使用過STL中的sort()函數,可能你會不明白我在說什么。。)
1 /* 2 *容器類 3 */ 4 template<typename elemType> 5 class Mylist 6 { 7 private: 8 int _size;//容器長度 9 Node<elemType> *head;//指向頭結點(不放數據) 10 Node<elemType> *_end;//指向容器的最后一個元素 11 bool (*cmp)(elemType a,elemType b);//指針函數,指向給定排序方式的函數 12 13 public: 14 Mylist() 15 { 16 head = new Node<elemType>(); 17 head->next = NULL; 18 _end = head; 19 this->_size = 0; 20 } 21 ~Mylist() 22 { 23 Node<elemType> *p,*tem; 24 p = head; 25 while( p != NULL) 26 { 27 tem = p; 28 p = p->next; 29 delete tem; 30 } 31 } 32 typedef Iter<elemType> iterator;//定義迭代器類型 33 void push_back(elemType data) 34 {//在容器的尾部添加元素 35 _end->next = new Node<elemType>(data); 36 _end = _end->next; 37 _size++; 38 } 39 void push_front(elemType data) 40 {//在容器的前端添加元素 41 Node<elemType> *p = new Node<elemType>(data); 42 p->next = head->next; 43 head->next = p; 44 if(head == _end) 45 _end = p; 46 _size++; 47 } 48 int size() 49 {//返回容器中的元素個數 50 return _size; 51 } 52 iterator begin() 53 {//返回一個迭代器,它指向容器的第一個元素 54 iterator iter(head->next); 55 return iter; 56 } 57 iterator end() 58 {//返返回一個迭代器,它指向容器的最后一個元素的下一位置 59 iterator iter(_end->next); 60 return iter; 61 } 62 bool erase(iterator iter) 63 {//刪除迭代器 iter 所指向的元素 64 Node<elemType> *p1 = iter.getNode(); 65 Node<elemType> *p2 = head; 66 while(p2->next != NULL) 67 { 68 if(p2->next == p1) 69 { 70 p2->next = p1->next; 71 if(_end == p1) 72 _end = p2; 73 delete p1; 74 p1 = NULL; 75 return true; 76 } 77 p2 = p2->next; 78 } 79 return false; 80 } 81 void clear() 82 {//清空容器 83 Node<elemType> *p,*tem; 84 p = head->next; 85 while( p != NULL) 86 { 87 tem = p; 88 p = p->next; 89 delete tem; 90 } 91 head->next = NULL; 92 _end = head; 93 } 94 /*******以下采用歸並算法實現了容器的排序操作*****/ 95 void sort(bool (*cmp)(elemType ,elemType )); 96 Node<elemType>* mergeSort(Node<elemType> *temHead); 97 Node<elemType>* merge(Node<elemType> *first,Node<elemType> *second); 98 }; 99 100 /* 101 *初始化排序函數指針 102 */ 103 template<typename elemType> 104 void Mylist<elemType>::sort(bool (*cmp)(elemType ,elemType )) 105 { 106 this->cmp = cmp; 107 head->next=mergeSort(head->next); 108 } 109 110 /* 111 *二分鏈表 112 */ 113 template<typename elemType> 114 Node<elemType>* Mylist<elemType>::mergeSort(Node<elemType> *temHead) 115 { 116 Node<elemType> *first; 117 Node<elemType> *second; 118 first=temHead; 119 second=temHead; 120 if(first==NULL||first->next==NULL) 121 { //若只有一個節點直接返回(遞歸臨界) 122 return first; 123 } 124 while(second->next!=NULL && second->next->next!=NULL) 125 { //利用一快一慢的指針把鏈表二分 126 first=first->next; //慢指針 127 second=second->next->next;//快指針 128 } 129 if(first->next!=NULL) 130 { 131 second=first->next; 132 first->next=NULL; 133 first=temHead; 134 } 135 return merge( mergeSort(first),mergeSort(second) ); //遞歸二分各個子鏈表 136 } 137 138 /* 139 *歸並兩路鏈表 140 */ 141 template<typename elemType> 142 Node<elemType>* Mylist<elemType>::merge(Node<elemType> *first,Node<elemType> *second) 143 {//注意到這里鏈表first,second已經是順序的了 144 Node<elemType> *resList=new Node<elemType>(); //開辟一個臨時頭節點 145 Node<elemType> *current; 146 current=resList; 147 while(first!=NULL && second!=NULL) 148 {//某一條鏈表空時結束 149 if((*cmp )(first->data,second->data)) 150 {//根據函數指針來確定排序方式 151 current->next=first; 152 current=current->next; 153 first=first->next; 154 } 155 else 156 { 157 current->next=second; 158 current=current->next; 159 second=second->next; 160 } 161 } 162 163 //把還剩下不空的鏈表繼續接到臨時頭結點所在的鏈表 164 while(first!=NULL) 165 { 166 current->next=first; 167 current=current->next; 168 first=first->next; 169 } 170 while(second!=NULL) 171 { 172 current->next=second; 173 current=current->next; 174 second=second->next; 175 } 176 current = resList->next; 177 delete resList;//記得釋放頭結點 178 return current; 179 }
四、測試程序

1 #include<iostream> 2 using namespace std; 3 4 template<typename elemType> 5 class Iter; 6 template<typename elemType> 7 class Mylist; 8 9 /* 10 *節點類 11 */ 12 template<typename elemType> 13 class Node 14 { 15 private: 16 elemType data; 17 Node *next; 18 public: 19 Node():next(NULL) 20 {} 21 Node(elemType data):data(data),next(NULL) 22 {} 23 //類Iter、Mylist要設為友元 24 friend class Iter<elemType>; 25 friend class Mylist<elemType>; 26 27 }; 28 29 30 /* 31 *迭代器類 32 */ 33 template<typename elemType> 34 class Iter 35 { 36 private: 37 Node<elemType> *node; 38 public: 39 Iter(){} 40 Iter(Node<elemType>* a):node(a){} 41 42 elemType operator *() const 43 {//*重載 44 return (node->data); 45 } 46 elemType * operator ->()const 47 {//重載迭代器->操作 48 return &(node->data); 49 } 50 bool operator !=(Iter<elemType> &a)const 51 {//重載迭代器!=操作 52 return node != a.node; 53 } 54 bool operator == (Iter<elemType> &a)const 55 {//重載迭代器==操作 56 return node == a.node; 57 } 58 Iter<elemType> operator++(int) 59 {//重載迭代器++作 60 Iter<elemType>tmp = *this; 61 this->node = this->node->next; 62 return tmp; 63 } 64 Node<elemType> * getNode(){ return node;} 65 }; 66 67 /* 68 *容器類 69 */ 70 template<typename elemType> 71 class Mylist 72 { 73 private: 74 int _size;//容器長度 75 Node<elemType> *head;//指向頭結點(不放數據) 76 Node<elemType> *_end;//指向容器的最后一個元素 77 bool (*cmp)(elemType a,elemType b);//指針函數,指向給定排序方式的函數 78 79 public: 80 Mylist() 81 { 82 head = new Node<elemType>(); 83 head->next = NULL; 84 _end = head; 85 this->_size = 0; 86 } 87 ~Mylist() 88 { 89 Node<elemType> *p,*tem; 90 p = head; 91 while( p != NULL) 92 { 93 tem = p; 94 p = p->next; 95 delete tem; 96 } 97 } 98 typedef Iter<elemType> iterator;//定義迭代器類型 99 void push_back(elemType data) 100 {//在容器的尾部添加元素 101 _end->next = new Node<elemType>(data); 102 _end = _end->next; 103 _size++; 104 } 105 void push_front(elemType data) 106 {//在容器的前端添加元素 107 Node<elemType> *p = new Node<elemType>(data); 108 p->next = head->next; 109 head->next = p; 110 if(head == _end) 111 _end = p; 112 _size++; 113 } 114 int size() 115 {//返回容器中的元素個數 116 return _size; 117 } 118 iterator begin() 119 {//返回一個迭代器,它指向容器的第一個元素 120 iterator iter(head->next); 121 return iter; 122 } 123 iterator end() 124 {//返返回一個迭代器,它指向容器的最后一個元素的下一位置 125 iterator iter(_end->next); 126 return iter; 127 } 128 bool erase(iterator iter) 129 {//刪除迭代器 iter 所指向的元素 130 Node<elemType> *p1 = iter.getNode(); 131 Node<elemType> *p2 = head; 132 while(p2->next != NULL) 133 { 134 if(p2->next == p1) 135 { 136 p2->next = p1->next; 137 if(_end == p1) 138 _end = p2; 139 delete p1; 140 p1 = NULL; 141 return true; 142 } 143 p2 = p2->next; 144 } 145 return false; 146 } 147 void clear() 148 {//清空容器 149 Node<elemType> *p,*tem; 150 p = head->next; 151 while( p != NULL) 152 { 153 tem = p; 154 p = p->next; 155 delete tem; 156 } 157 head->next = NULL; 158 _end = head; 159 } 160 /*******以下采用歸並算法實現了容器的排序操作*****/ 161 void sort(bool (*cmp)(elemType ,elemType )); 162 Node<elemType>* mergeSort(Node<elemType> *temHead); 163 Node<elemType>* merge(Node<elemType> *first,Node<elemType> *second); 164 }; 165 166 /* 167 *初始化排序函數指針 168 */ 169 template<typename elemType> 170 void Mylist<elemType>::sort(bool (*cmp)(elemType ,elemType )) 171 { 172 this->cmp = cmp; 173 head->next=mergeSort(head->next); 174 while(_end->next != NULL) 175 {//記得更新_end指向 176 _end = _end->next; 177 } 178 } 179 180 /* 181 *二分鏈表 182 */ 183 template<typename elemType> 184 Node<elemType>* Mylist<elemType>::mergeSort(Node<elemType> *temHead) 185 { 186 Node<elemType> *first; 187 Node<elemType> *second; 188 first=temHead; 189 second=temHead; 190 if(first==NULL||first->next==NULL) 191 { //若只有一個節點直接返回(遞歸臨界) 192 return first; 193 } 194 while(second->next!=NULL && second->next->next!=NULL) 195 { //利用一快一慢的指針把鏈表二分 196 first=first->next; //慢指針 197 second=second->next->next;//快指針 198 } 199 if(first->next!=NULL) 200 { 201 second=first->next; 202 first->next=NULL; 203 first=temHead; 204 } 205 return merge( mergeSort(first),mergeSort(second) ); //遞歸二分各個子鏈表 206 } 207 208 /* 209 *歸並兩路鏈表 210 */ 211 template<typename elemType> 212 Node<elemType>* Mylist<elemType>::merge(Node<elemType> *first,Node<elemType> *second) 213 {//注意到這里鏈表first,second已經是順序的了 214 Node<elemType> *resList=new Node<elemType>(); //開辟一個臨時頭節點 215 Node<elemType> *current; 216 current=resList; 217 while(first!=NULL && second!=NULL) 218 {//某一條鏈表空時結束 219 if((*cmp )(first->data,second->data)) 220 {//根據函數指針來確定排序方式 221 current->next=first; 222 current=current->next; 223 first=first->next; 224 } 225 else 226 { 227 current->next=second; 228 current=current->next; 229 second=second->next; 230 } 231 } 232 233 //把還剩下不空的鏈表繼續接到臨時頭結點所在的鏈表 234 while(first!=NULL) 235 { 236 current->next=first; 237 current=current->next; 238 first=first->next; 239 } 240 while(second!=NULL) 241 { 242 current->next=second; 243 current=current->next; 244 second=second->next; 245 } 246 current = resList->next; 247 delete resList;//記得釋放頭結點 248 return current; 249 } 250 251 252 bool cmp(int a, int b) 253 {//從小到大排序 254 return a <= b; 255 } 256 int main(int argc, char** argv) 257 { 258 Mylist<int> test; 259 Mylist<int>::iterator iter; 260 for(int i = 0; i < 10; i++) 261 { 262 i < 5 ? test.push_back(i): test.push_front(i); 263 } 264 cout<<"未排序:"; 265 for(iter = test.begin(); iter != test.end(); iter++) 266 { 267 printf("%d ", *iter); 268 } 269 cout<<endl; 270 test.sort(cmp); 271 cout<<"已排序:"; 272 for(iter = test.begin(); iter != test.end(); iter++) 273 { 274 printf("%d ", *iter); 275 } 276 cout<<endl; 277 return 0; 278 }
運行結果如下: