zoukankan      html  css  js  c++  java
  • 第二十九课 循环链表的实现

    循环链表的继承层次结构:

    插入位置为0图解:

     删除位置为0图解:

     添加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     int mod(int i) const   // 不能对0取余,需特殊处理
     16     {
     17         return (this->m_length == 0) ? 0 : (i % this->m_length);
     18     }
     19 
     20     // last获取最后一个节点的指针
     21     // position返回i-1个节点,再取next可以获取最后一个节点的指针
     22     Node* last() const
     23     {
     24         return this->position(this->m_length - 1)->next;
     25     }
     26 
     27     void last_to_first() const    //将链表首尾相连
     28     {
     29         last()->next = this->m_header.next;
     30     }
     31 
     32 public:
     33     bool insert(const T& e)
     34     {
     35         return insert(this->m_length, e);
     36     }
     37 
     38     bool insert(int i, const T& e)
     39     {
     40         bool ret = true;
     41 
     42         i = i % (this->m_length + 1);
     43 
     44         ret = LinkList<T>::insert(i, e);
     45 
     46         if(ret && (i == 0))
     47         {
     48             last_to_first();
     49         }
     50 
     51         return ret;
     52     }
     53 
     54     bool remove(int i)
     55     {
     56         bool ret = true;
     57 
     58         i = mod(i);
     59 
     60         if(i == 0)
     61         {
     62             Node* toDel = this->m_header.next;
     63 
     64             if( toDel != NULL )
     65             {
     66                 this->m_header.next = toDel->next;
     67                 this->m_length--;
     68 
     69                 if( this->m_length > 0 )
     70                 {
     71                     last_to_first();
     72 
     73                     if( this->m_current == toDel )
     74                     {
     75                         this->m_current = toDel->next;
     76                     }
     77                 }
     78                 else
     79                 {
     80                     this->m_header.next = NULL;
     81                     this->m_current = NULL;
     82                 }
     83 
     84                 this->destroy(toDel);
     85             }
     86             else
     87             {
     88                 ret = false;
     89             }
     90         }
     91         else
     92         {
     93             ret = LinkList<T>::remove(i);
     94         }
     95 
     96         return ret;
     97     }
     98 
     99     bool set(int i, const T& e)
    100     {
    101         return LinkList<T>::set(mod(i), e);
    102     }
    103 
    104     T get(int i) const
    105     {
    106         return LinkList<T>::get(mod(i));
    107     }
    108 
    109     bool get(int i, T& e) const
    110     {
    111         return LinkList<T>::get(mod(i), e);
    112     }
    113 
    114     int find(const T& e) const
    115     {
    116         int ret = -1;
    117 
    118         //先变成单链表,这样就可以直接调用find了,find过后再恢复为循环链表
    119         //但是这是有问题的,因为find中可能抛出异常
    120         //last()->next = NULL;
    121         //ret = LinkList<T>::find(e);
    122         //last_to_first();
    123 
    124         Node* slider = this->m_header.next;
    125 
    126         for(int i = 0; i < this->m_length; i++)
    127         {
    128             if( slider->value == e )
    129             {
    130                 ret = i;
    131                 break;
    132             }
    133 
    134             slider = slider->next;
    135         }
    136 
    137         return ret;
    138     }
    139 
    140     void clear()
    141     {
    142         while( this->m_length > 1)
    143         {
    144             remove(1);   // 每次删除第一个元素,提高效率,每次删除第0个元素效率低
    145         }
    146 
    147         if( this->m_length == 1)
    148         {
    149             Node* toDel = this->m_header.next;
    150 
    151             this->m_header.next = NULL;
    152             this->m_length = 0;
    153             this->m_current = NULL;
    154 
    155             this->destroy(toDel);
    156         }
    157     }
    158 
    159     bool move(int i, int step)
    160     {
    161         return LinkList<T>::move(mod(i), step);
    162     }
    163 
    164     bool end()
    165     {
    166         return (this->m_length == 0) || (this->m_current == NULL);
    167     }
    168 
    169     ~CircleList()
    170     {
    171         clear();
    172     }
    173 };
    174 
    175 }
    176 
    177 #endif // CIRCLELIST_H

    我们将LinkList中的函数全部做成了virtual虚函数,因为有可能将CircleList当LinkList使用。在CircleList中我们重新实现了很多函数。

    在重新实现的find函数中,120--122行也能实现功能,但是这不是异常安全的,先将循环链表变为单链表,然后查找,最后再变为循环链表。在查找的过程中有泛指类型T的比较操作,因此,有可能抛出异常。抛出异常后就无法变为循环链表了,破坏了循环链表,因此,不是异常安全的。为了移植性,我们也不选择使用try catch,而是重新实现了find函数。

    mod函数要定义为const的,否则在get成员函数中使用mod会报错。

    例如:

    CircleList的clear函数也是重新实现,不能直接变为单链表,然后调用父类的clear,因为也存在异常安全性。

    我们重新实现了clear,在m_length大于1时,每次删除第一个元素,这样可以提高效率。如果每次删除第0个元素,则还要涉及到 last_to_first操作,这时效率非常低的。

    循环链表的应用:

    测试程序如下:

     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     // 报数到m就自杀,也就是移动m-1次就自杀,因此,下面传入的参数是m-1
    17     cl.move(s-1, m - 1);
    18 
    19     while( cl.length() > 0 )
    20     {
    21         cl.next();
    22         cout << cl.current() << endl;
    23         cl.remove(cl.find(cl.current()));
    24     }
    25 }
    26 
    27 int main()
    28 {
    29     //41个人玩游戏, 从1开始数数, 数到3就自杀
    30     josephus(41, 1, 3);
    31 
    32     return 0;
    33 }

    运行结果如下:

    小结:

  • 相关阅读:
    数据恢复:解决ORA600[kghstack_free2][kghstack_err+0068]一例
    Oracle latch闩原理示意图
    MySQL Query Analyzer查询分析器
    Oracle GoldenGate Monitor架构图
    Oracle Row cache lock图解
    没有Metalink账号的同学可以观赏下,My Oracle Support的主界面
    Oracle Goldengate Director软件截面图
    Oracle Unbreakable Enterprise Kernel Faster than Redhat?
    从Win32过渡到MFC
    naked 函数调用
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9654997.html
Copyright © 2011-2022 走看看