实现一个简单的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一个。
冒泡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 }
四、测试程序
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
运行结果如下: