第29课 - 循环链表的实现

1、循环链表的实现 

            什么是循环链表? 

                -概念上 

                            任意数据元素都有—个前驱和—个后维 

                            所有的数据元素的关系构成—个逻辑上的环 

                -实现上 

                            循环链表是一种特殊的单链表 

                            尾结点的指针域保存了首结点的地址


            循环链表的逻辑构成 



            循环链表的继承层次结构



        循环链表的实现思路

                -通过模板定义CircleList类,维承自LinkList类 

                -定义内部函数last_to_first() , 用于将单链表首尾相连 

                -特殊处理:首元素的插入操作和删除操作 

                - 重新实现:清空操作和遍历操作 


        循环链表的实现要点 

            -插入位置为0时: 

                        头结点和尾结点均指向新结点 

                        新结点成为首结点插入链表 

            -删除位置为0时

                        头结点和尾结点指向位置为1的结点 

                        安全销毁首结点


2、编程实验 

循环链表的实现     CircleList.h 

  1. #ifndef CIRCLELIST_H  
  2. #define CIRCLELIST_H  
  3.   
  4. #include"LinkList.h"  
  5.   
  6. namespace DTLib  
  7. {  
  8.   
  9. template <typename T>  
  10. class CircleList : public LinkList<T>  
  11. {  
  12. protected:  
  13.     typedef typename LinkList<T>::Node Node;  
  14.   
  15.     Node* last() const  //O(n)  
  16.     {  
  17.         return this->position(this->m_length-1)->next;      //返回尾结点地址  
  18.     }  
  19.     void last_to_first() const  //O(n)  
  20.     {  
  21.         last()->next = this->m_header.next;  
  22.     }  
  23.   
  24.     int mod(int i) const    //O(1)  
  25.     {  
  26.         return (this->m_length == 0) ? 0 : (i % this->m_length);  
  27.     }  
  28.   
  29. public:  
  30.     bool insert(const T& e)     //O(n)  
  31.     {  
  32.         return insert(this->m_length,e);  
  33.     }  
  34.     bool insert(int i,const T& e)   //O(2n+1) ==> O(n)  
  35.     {  
  36.         bool ret = true;  
  37.   
  38.         i = i % (this->m_length + 1);       //O(1)  
  39.   
  40.         ret = LinkList<T>::insert(i,e);    //先正常插入  O(n)  
  41.   
  42.         if(ret && (i == 0))  
  43.         {  
  44.             last_to_first();    //O(n)  
  45.         }  
  46.   
  47.         return ret;  
  48.     }  
  49.     bool remove(int i)  //O(n)  
  50.     {  
  51.         bool ret = true;  
  52.   
  53.         i = mod(i);  
  54.   
  55.         if(i == 0)    
  56.         {  
  57.             Node* toDel = this->m_header.next;  
  58.   
  59.             if(toDel != NULL)  
  60.             {  
  61.                 this->m_header.next = toDel->next;  
  62.                 this->m_length--;  
  63.   
  64.                 if(this->m_length > 0)  
  65.                 {  
  66.                     last_to_first();        //O(n)  
  67.   
  68.                     if(toDel == this->m_current)  
  69.                     {  
  70.                         this->m_current = toDel->next;  
  71.                     }  
  72.                 }  
  73.                 else  
  74.                 {  
  75.                     this->m_header.next = NULL;  
  76.                     this->m_current = NULL;  
  77.                 }  
  78.   
  79.                 this->destroy(toDel);  
  80.             }  
  81.             else  
  82.             {  
  83.                 ret = false;  
  84.             }  
  85.         }  
  86.         else  
  87.         {  
  88.             ret = LinkList<T>::remove(i);   //O(n)  
  89.         }  
  90.   
  91.         return ret;  
  92.     }  
  93.     bool set(int i,const T& e)      //O(n)  
  94.     {  
  95.         return LinkList<T>::set(mod(i),e);  
  96.     }  
  97.     T get(int i) const      //O(n)  
  98.     {  
  99.         return LinkList<T>::get(mod(i));  
  100.     }  
  101.     bool get(int i,const T& e) const        //O(n)  
  102.     {  
  103.         return LinkList<T>::get(mod(i),e);  
  104.     }  
  105.  /*   int find(const T& e) 
  106.     { 
  107.         int ret = -1; 
  108.  
  109.         last()->next = NULL;    //变为单链表 
  110.  
  111.         ret = LinkList<T>::find(e); 
  112.  
  113.         last_to_first(); 
  114.  
  115.         return ret; 
  116.     } 
  117. */  
  118.     /* 
  119.      * 不安全,直接调用父类的find函数,在" == "比较时有可能 
  120.      * 比较的是对象,即需要重载函数,可能抛异常,无法进行 
  121.      * last_to_first操作,循环链表状态直接被改变 
  122.      */  
  123.     int find(const T& e)        //O(n)  
  124.     {  
  125.         int ret = -1;  
  126.   
  127.         Node* slider = this->m_header.next;  
  128.   
  129.         for(int i=0;i<this->m_length;i++)  
  130.         {  
  131.             if(slider->value == e)      //即便抛异常也不会改变循环链表状态  
  132.             {  
  133.                 ret = i;  
  134.                 break;  
  135.             }  
  136.             slider = slider->next;  
  137.         }  
  138.   
  139.         return ret;  
  140.     }  
  141. /*    void clear() 
  142.     { 
  143.         if(this->m_length > 0) 
  144.         { 
  145.             last()->next = NULL; 
  146.             LinkList<T>::clear(); 
  147.         } 
  148.     } 
  149. */  
  150.     void clear()    //O(n)  
  151.     {  
  152.         while(this->m_length > 1)       //O(n)  
  153.         {  
  154.             remove(1);//不remove(0)的原因是效率            //O(1)  
  155.         }  
  156.   
  157.         if(this->m_length == 1) //O(1)  
  158.         {  
  159.             Node* toDel = this->m_header.next;  
  160.   
  161.             this->m_header.next = NULL;  
  162.             this->m_current = NULL;  
  163.             this->m_length = 0;  
  164.   
  165.             this->destroy(toDel);  
  166.         }  
  167.     }  
  168.     bool move(int i,int step)   //O(n)  
  169.     {  
  170.         return LinkList<T>::move(mod(i),step);  
  171.     }  
  172.     bool end()  //O(1)  
  173.     {  
  174.         return ( (this->m_length == 0) || (this->m_current == NULL) );  
  175.     }  
  176.   
  177.     ~CircleList()   //O(n)  
  178.     {  
  179.         clear();  
  180.     }  
  181.   
  182. };  
  183.   
  184.   
  185. }  
  186. #endif // CIRCLELIST_H  


修改LinkList.h

  1. #ifndef LINKLIST_H  
  2. #define LINKLIST_H  
  3.   
  4. #include"List.h"  
  5. #include"Exception.h"  
  6.   
  7. namespace DTLib  
  8. {  
  9.   
  10. template <typename T>  
  11. class LinkList : public List<T>  
  12. {  
  13. protected:  
  14.     struct Node : public Object  
  15.     {  
  16.         T value;  
  17.         Node* next;  
  18.     };  
  19.     mutable struct : public Object  //保证内存布局一致  
  20.     {  
  21.         char reserved[sizeof(T)];   //木有实际作用,仅仅占空间,保证内存布局和Node一样  
  22.         Node* next;  
  23.     }m_header;  
  24.   
  25.     int m_length;  
  26.   
  27.     Node* m_current;  
  28.     int m_step;  
  29.   
  30.     Node* position(int i) const     //定位到i的前一个结点位置  
  31.     {  
  32.         Node* ret  = reinterpret_cast<Node*>(&m_header);  
  33.   
  34.         for(int p=0;p<i;p++)  
  35.         {  
  36.             ret = ret->next;  
  37.         }  
  38.   
  39.         return ret;  
  40.     }  
  41.   
  42.     virtual Node* create()  
  43.     {  
  44.         return new Node();  
  45.     }  
  46.     virtual void destroy(Node* pn)  
  47.     {  
  48.         delete pn;  
  49.     }  
  50.   
  51. public:  
  52.     LinkList()  
  53.     {  
  54.         m_header.next = NULL;  
  55.         m_length = 0;  
  56.         m_step = 1;  
  57.         m_current = NULL;  
  58.     }  
  59.     bool insert(int i,const T& e)  
  60.     {  
  61.         bool ret = (0 <= i)&&(i <= m_length);  
  62.   
  63.         if(ret)  
  64.         {  
  65.             Node* node = create();  
  66.   
  67.             if( node )  
  68.             {  
  69.                 Node* current = position(i);  
  70.   
  71.                 node->value = e;  
  72.                 node->next = current->next;  
  73.                 current->next = node;  
  74.   
  75.                 m_length++;  
  76.             }  
  77.             else  
  78.             {  
  79.                 THROW_EXCEPTION(NoEnoughMemoryException,"No memory to insert new element ...");  
  80.             }  
  81.         }  
  82.   
  83.         return ret;  
  84.     }  
  85.     bool insert(const T& e)  
  86.     {  
  87.         return insert(m_length,e);  
  88.     }  
  89.     bool remove(int i)  
  90.     {  
  91.         bool ret = (0 <= i)&&(i < m_length);  
  92.   
  93.         if(ret)  
  94.         {  
  95.             Node* current = position(i);  
  96.   
  97.             Node* toDel = current->next;  
  98.   
  99.             if(m_current == toDel)  
  100.             {  
  101.                 m_current = toDel->next;    //游标指向下一个数据元素即可  
  102.             }  
  103.   
  104.             current->next = toDel->next;  
  105.   
  106.             m_length--;  
  107.   
  108.             destroy(toDel);  
  109.   
  110.         }  
  111.   
  112.         return ret;  
  113.     }  
  114.     bool set(int i,const T& e)  
  115.     {  
  116.         bool ret = (0 <= i)&&(i < m_length);  
  117.   
  118.         if(ret)  
  119.         {  
  120.             position(i)->next->value = e;  
  121.         }  
  122.   
  123.         return ret;  
  124.     }  
  125.     virtual T get(int i) const  
  126.     {  
  127.         T ret;  
  128.   
  129.         if(get(i,ret))  
  130.         {  
  131.             return ret;  
  132.         }  
  133.         else  
  134.         {  
  135.             THROW_EXCEPTION(IndexOutOfBoundsExpception,"Invalid parameter i to get element ...");  
  136.         }  
  137.   
  138.         return ret;  
  139.     }  
  140.     bool get(int i,T& e) const  
  141.     {  
  142.         bool ret = (0 <= i)&&(i < m_length);  
  143.   
  144.         if(ret)  
  145.         {  
  146.             e = position(i)->next->value;   //position 为 const 成员函数  
  147.         }  
  148.   
  149.         return ret;  
  150.     }  
  151.     int find(const T& e) const  
  152.     {  
  153.         int ret = -1;  
  154.         int i = 0;  
  155.   
  156.         Node* node = m_header.next;  
  157.   
  158.         while( node )  
  159.         {  
  160.             if(node->value == e)  
  161.             {  
  162.                 ret = i;  
  163.                 break;  
  164.             }  
  165.             else  
  166.             {  
  167.                 node = node->next;  
  168.   
  169.                 i++;  
  170.             }  
  171.         }  
  172.   
  173.         return ret;  
  174.     }  
  175.     int length() const  
  176.     {  
  177.         return m_length;  
  178.     }  
  179.   
  180.     void clear()  
  181.     {  
  182.         while( m_header.next )  
  183.         {  
  184.             Node* toDel = m_header.next;  
  185.             m_header.next = toDel->next;  
  186.   
  187.             m_length--;  
  188.   
  189.             destroy(toDel);  
  190.         }  
  191.     }  
  192.     virtual bool move(int i,int step = 1)  
  193.     {  
  194.         bool ret = (0 <= i)&&(i < m_length)&&(step > 0);  
  195.   
  196.         if(ret)  
  197.         {  
  198.             m_current = position(i)->next;  
  199.             m_step = step;  
  200.         }  
  201.   
  202.         return ret;  
  203.     }  
  204.     virtual bool end()  
  205.     {  
  206.         return ( m_current == NULL);  
  207.     }  
  208.     virtual T current()  
  209.     {  
  210.         if(!end())  //if( m_current != NULL )  
  211.         {  
  212.             return m_current->value;  
  213.         }  
  214.         else  
  215.         {  
  216.             THROW_EXCEPTION(InvalidParameterException,"No value at current position ...");  
  217.         }  
  218.     }  
  219.     virtual bool next()  
  220.     {  
  221.         int i = 0;  
  222.         while((i < m_step) && !end())  
  223.         {  
  224.             m_current = m_current->next;  
  225.             i++;  
  226.         }  
  227.   
  228.         return (i == m_step);  
  229.     }  
  230.   
  231.     ~LinkList()  
  232.     {  
  233.         clear();    //构造函数析构函数不会发生多态,destroy调用的父类  
  234.     }  
  235. };  
  236. }  
  237. #endif // LINKLIST_H  


3、循环链表的应用 

            -约瑟夫环问题 

                    已知n个人(以编号0, 1 , 2 , 3 ,…,n-1分别表示)围坐在—张圆桌周围。

                    从编号为k的人开始报数,数到m的那个人出列;他的 下—个人又从1开始报数,

                    数到m的那个人又出列;依此规律重复 下去,直到圆桌周围的入全部出列。 


            小故事

                    在罗马人占领乔塔帕特后,39个犹太人与 Josephus及他的朋友躲到一个洞中,39个犹大人 

                    决定宁愿死也不要被敌人抓到,于是决定了一个 自杀方式,41个人排成一个圆圈,由第1个人开始 

                    报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。 

                     然而Josephus和他的朋友并不想遵从。那么,一开始要站在什么地方才能避免被处决? 


4、编程实验 

约瑟夫问题     main.cpp

  1. #include <iostream>  
  2. #include"CircleList.h"  
  3.   
  4. using namespace std;  
  5. using namespace DTLib;  
  6.   
  7. void josephus(int n ,int s,int m)  
  8. {  
  9.     CircleList<int> cl;  
  10.   
  11.     for(int i=1;i<=n;i++)  
  12.     {  
  13.         cl.insert(i);  
  14.     }  
  15.       
  16.     cl.move(s-1,m-1);  
  17.   
  18.     while(cl.length() > 0)  
  19.     {  
  20.         cl.next();  
  21.   
  22.         cout<<cl.current()<<"  ";  
  23.   
  24.         cl.remove(cl.find(cl.current()));  
  25.     }  
  26.   
  27. }  
  28.   
  29. int main()  
  30. {  
  31.     josephus(41,1,3);  
  32.   
  33.   
  34.     return 0;  
  35. }  




5、小结 

            循环链表是—种特殊的单链表 

            尾结点的指针域保存了首结点的地址 

            特殊处理首元素的插入操作和删除操作 

            重新实现清空操作和追历操作


猜你喜欢

转载自blog.csdn.net/qq_39654127/article/details/80264980