實現一個簡單的c++ list容器(含sort排序 鏈表歸並算法實現)


      這個其實是很久之前寫的,最近參加面試,復習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一個。

冒泡ON^2,相比於歸並最壞情形運行時間:ONlogN,當問題規模變大時,冒泡顯然是吃不消的。

首先是遞歸二分鏈表,遞歸到最后會把鏈表分為一個個長度為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 }

 

 

 

 四、測試程序

View Code
  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 }

運行結果如下:

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM