• 实现一个简单的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 }

    运行结果如下:

  • 相关阅读:
    selenium server在页面加载超时浏览器与driver通信失败时的妙用
    selenium并行的使用
    selenium代理
    selenium鼠标拖动
    做事要是专业
    selenium select 标签选中
    从字符串中提取数字
    selenium中Alter等弹出对话框的处理
    Selenium资料
    P2048 [NOI2010]超级钢琴 (RMQ,堆)
  • 原文地址:https://www.cnblogs.com/zxj015/p/2775996.html
Copyright © 2020-2023  润新知