數據結構基礎(11) --循環鏈表的設計與實現

循環鏈表:最後一個結點的指針域的指針又指回第一個結點的鏈表;

    循環單鏈表與單鏈表的區別在於:表中最有一個節點的指針不再是NULL, 而改爲指向頭結點(因此要對我們原來的MyList稍作修改), 從而整個鏈表形成一個環.

    因此, 循環單鏈表的判空條件不再是頭結點的指針是否爲空, 而是他是否等於頭結點;

    其實如果只是單純的實現循環鏈表對單鏈表的性能提升是不明顯的, 反而增加了代碼上實現的複雜度, 但是如果與下一篇中的雙向鏈表相結合的話, 在速度上的提升是十分驚人的, 因此這篇博客權當做是一個過渡吧, 爲上一篇博客和下一篇博客的結合起着承上啓下的作用.

 

    下面是MyList.h的完整代碼與解析, 由於代碼較多, 希望能夠仔細閱讀, 但其實下面的大部分代碼都與前面類似只是對其中幾處稍作修改, 遇到與單鏈表的不同之處, 我會與++符號作爲註釋指出:

[cpp] view plain copy
  1. #ifndef MYLIST_H_INCLUDED  
  2. #define MYLIST_H_INCLUDED  
  3.   
  4. #include <iostream>  
  5. #include <stdexcept>  
  6. using namespace std;  
  7.   
  8. //循環鏈表  
  9. //前向聲明  
  10. template <typename Type>  
  11. class MyList;  
  12. template <typename Type>  
  13. class ListIterator;  
  14.   
  15. //鏈表節點  
  16. template <typename Type>  
  17. class Node  
  18. {  
  19.     //可以將MyList類作爲Node的友元  
  20.     //同時也可以將Node類做成MyList的嵌套類, 嵌套在MyList中, 也可以完成該功能  
  21.     friend class MyList<Type>;  
  22.     friend class ListIterator<Type>;  
  23.   
  24.     template <typename T>  
  25.     friend ostream &operator<<(ostream &os, const MyList<T> &list);  
  26. private:  
  27.     //constructor說明:  
  28.     //next = NULL;    //因爲這是一個新生成的節點, 因此下一個節點爲空  
  29.     Node(const Type &dataValue):data(dataValue), next(NULL) {}  
  30.   
  31.     Type data;  //數據域:節點數據  
  32.     Node *next; //指針域:下一個節點  
  33. };  
  34.   
  35. //鏈表  
  36. template <typename Type>  
  37. class MyList  
  38. {  
  39.     template <typename T>  
  40.     friend ostream &operator<<(ostream &os, const MyList<T> &list);  
  41.   
  42.     friend class ListIterator<Type>;  
  43. public:  
  44.     MyList();  
  45.     ~MyList();  
  46.   
  47.     //將元素插入表頭  
  48.     void insertFront(const Type &data);  
  49.     //將元素插入到位置index上(index從1開始)  
  50.     void insert(const Type &data, int index);  
  51.     //刪除表中所有值爲data的節點  
  52.     void remove(const Type &data);  
  53.     bool isEmpty() const;  
  54.   
  55. private:  
  56.     //指向第一個節點的指針  
  57.     Node<Type> *first;  
  58. };  
  59.   
  60. template <typename Type>  
  61. MyList<Type>::MyList()  
  62. {  
  63.     //first指向一個空節點  
  64.     first = new Node<Type>(0);  
  65.   
  66.     // ++ 這是一個關鍵點  
  67.     //first的下一個元素就指向first  
  68.     //此時, 代表鏈表是否已經到達結尾處的判斷已經不再是(是否等於NULL)  
  69.     //而改爲(是否等於first)  
  70.     //因爲此時first代表鏈表的最後一個元素  
  71.     //同時,first又是第一個元素的前一個元素  
  72.     first -> next = first;  
  73. }  
  74.   
  75. template <typename Type>  
  76. MyList<Type>::~MyList()  
  77. {  
  78.     Node<Type> *deleteNode = NULL;  
  79.     // ++ 保存鏈表尾元素  
  80.     Node<Type> *tmp = first;  
  81.   
  82.     // ++ first首先指向第一個真實的元素  
  83.     first = first->next;  
  84.     //一路到達鏈表結尾  
  85.     while (first != tmp)  
  86.     {  
  87.         deleteNode = first;  
  88.         first = first -> next;  
  89.         delete deleteNode;  
  90.     }  
  91.     // ++ 釋放到鏈表的空節點  
  92.     delete tmp;  
  93. }  
  94.   
  95. //這一步與前一版鏈表相同  
  96. template <typename Type>  
  97. void MyList<Type>::insertFront(const Type &data)  
  98. {  
  99.     Node<Type> *newNode = new Node<Type>(data);  
  100.     newNode -> next = first -> next;  
  101.     first -> next = newNode;  
  102. }  
  103.   
  104. template <typename Type>  
  105. void MyList<Type>::insert(const Type &data, int index)  
  106. {  
  107.     //由於我們在表頭添加了一個空節點  
  108.     //因此如果鏈表爲空, 或者在鏈表爲1的位置添加元素  
  109.     //其操作與在其他位置添加元素相同  
  110.   
  111.     int count = 1;  
  112.     //此時searchNode肯定不爲first  
  113.     Node<Type> *searchNode = first;  
  114.   
  115.     //++ 注意:此處將NULL修改爲first  
  116.     // 找到要插入的位置  
  117.     // 如果所給index過大(超過了鏈表的長度)  
  118.     // 則將該元素插入到鏈表表尾  
  119.     // 原因是 searchNode->next != first 這個條件已經不滿足了  
  120.     while (count < index && searchNode->next != first)  
  121.     {  
  122.         ++ count;  
  123.         searchNode = searchNode->next;  
  124.     }  
  125.   
  126.     // 插入鏈表  
  127.     Node<Type> *newNode = new Node<Type>(data);  
  128.     newNode->next = searchNode->next;  
  129.     searchNode->next = newNode;  
  130. }  
  131.   
  132. template <typename Type>  
  133. void MyList<Type>::remove(const Type &data)  
  134. {  
  135.     if (isEmpty())  
  136.         return ;  
  137.   
  138.     Node<Type> *previous = first;   //保存要刪除節點的前一個節點  
  139.     for (Node<Type> *searchNode = first->next;  
  140.             //searchNode != NULL; // ++ 注意此處不再是判斷是否爲NULL  
  141.             searchNode != first;     // ++ 而是不能等於first, first代表鏈表的末尾  
  142.             searchNode = searchNode->next)  
  143.     {  
  144.         if (searchNode->data == data)  
  145.         {  
  146.             previous->next = searchNode->next;  
  147.             delete searchNode;  
  148.             //重新調整searchNode指針  
  149.             //繼續遍歷鏈表查看是否還有相等元素  
  150.   
  151.             // ++ 注意  
  152.             //如果當前searchNode已經到達了最後一個節點  
  153.             //也就是searchNode->next已經等於first了, 則下面這條語句不能執行  
  154.             if (previous->next == first)  
  155.                 break;  
  156.   
  157.             searchNode = previous->next;  
  158.         }  
  159.         previous = searchNode;  
  160.     }  
  161. }  
  162. //注意判空條件  
  163. template <typename Type>  
  164. bool MyList<Type>::isEmpty() const  
  165. {  
  166.     return first->next == first;  
  167. }  
  168.   
  169. //顯示鏈表中的所有數據(測試用)  
  170. template <typename Type>  
  171. ostream &operator<<(ostream &os, const MyList<Type> &list)  
  172. {  
  173.     for (Node<Type> *searchNode = list.first -> next;  
  174.             searchNode != list.first;   //++ 注意  
  175.             searchNode = searchNode -> next)  
  176.     {  
  177.         os << searchNode -> data;  
  178.         if (searchNode -> next != list.first) // ++ 注意(尚未達到鏈表的結尾)  
  179.             cout << " -> ";  
  180.     }  
  181.   
  182.     return os;  
  183. }  
  184.   
  185. //ListIterator 除了判空函數的判空條件之外, 沒有任何改變  
  186. template <typename Type>  
  187. class ListIterator  
  188. {  
  189. public:  
  190.     ListIterator(const MyList<Type> &_list):  
  191.         list(_list),  
  192.         currentNode((_list.first)->next) {}  
  193.   
  194.     //重載 *operator  
  195.     const Type &operator*() const throw (std::out_of_range);  
  196.     Type &operator*() throw (std::out_of_range);  
  197.   
  198.     //重載 ->operator  
  199.     const Node<Type> *operator->() const throw (std::out_of_range);  
  200.     Node<Type> *operator->() throw (std::out_of_range);  
  201.   
  202.     //重載 ++operator  
  203.     ListIterator &operator++() throw (std::out_of_range);  
  204.     //注意:此處返回的是值,而不是reference  
  205.     ListIterator operator++(intthrow (std::out_of_range);  
  206.   
  207.     bool isEmpty() const;  
  208.   
  209. private:  
  210.     const MyList<Type> &list;  
  211.     Node<Type> *currentNode;  
  212. };  
  213.   
  214. template <typename Type>  
  215. bool ListIterator<Type>::isEmpty() const  
  216. {  
  217.     // ++ 注意:判空條件改爲list.first  
  218.     if (currentNode == list.first)  
  219.         return true;  
  220.     return false;  
  221. }  
  222. template <typename Type>  
  223. const Type &ListIterator<Type>::operator*() const  
  224. throw (std::out_of_range)  
  225. {  
  226.     if (isEmpty())  
  227.         throw std::out_of_range("iterator is out of range");  
  228.     // 返回當前指針指向的內容  
  229.     return currentNode->data;  
  230. }  
  231. template <typename Type>  
  232. Type &ListIterator<Type>::operator*()  
  233. throw (std::out_of_range)  
  234. {  
  235.     //首先爲*this添加const屬性,  
  236.     //以調用該函數的const版本,  
  237.     //然後再使用const_case,  
  238.     //將該函數調用所帶有的const屬性轉除  
  239.     //operator->()的non-const版本與此類同  
  240.     return  
  241.         const_cast<Type &>(  
  242.             static_cast<const ListIterator<Type> &>(*this).operator*()  
  243.         );  
  244. }  
  245.   
  246. template <typename Type>  
  247. const Node<Type> *ListIterator<Type>::operator->() const  
  248. throw (std::out_of_range)  
  249. {  
  250.     if (isEmpty())  
  251.         throw std::out_of_range("iterator is out of range");  
  252.     //直接返回指針  
  253.     return currentNode;  
  254. }  
  255.   
  256. template <typename Type>  
  257. Node<Type> *ListIterator<Type>::operator->()  
  258. throw (std::out_of_range)  
  259. {  
  260.     // 見上  
  261.     return  
  262.         const_cast<Node<Type> *> (  
  263.             static_cast<const ListIterator<Type> >(*this).operator->()  
  264.         );  
  265. }  
  266.   
  267. template <typename Type>  
  268. ListIterator<Type> &ListIterator<Type>::operator++()  
  269. throw (std::out_of_range)  
  270. {  
  271.     if (isEmpty())  
  272.         throw std::out_of_range("iterator is out of range");  
  273.     //指針前移  
  274.     currentNode = currentNode->next;  
  275.     return *this;  
  276. }  
  277. template <typename Type>  
  278. ListIterator<Type> ListIterator<Type>::operator++(int)  
  279. throw (std::out_of_range)  
  280. {  
  281.     ListIterator tmp(*this);  
  282.     ++ (*this); //調用前向++版本  
  283.   
  284.     return tmp;  
  285. }  
  286.   
  287. #endif // MYLIST_H_INCLUDED  

附-測試代碼:

[cpp] view plain copy
  1. int main()  
  2. {  
  3.     MyList<int> iMyList;  
  4.     for (int i = 0; i < 10; ++i)    //1 2 3 4 5 6 7 8 9 10  
  5.         iMyList.insert(i+1, i+1);  
  6.   
  7.     for (int i = 0; i < 5; ++i)     //40 30 20 10 0 1 2 3 4 5 6 7 8 9 10  
  8.         iMyList.insertFront(i*10);  
  9.   
  10.     iMyList.insertFront(100);//100 40 30 20 10 0 1 2 3 4 5 6 7 8 9 10  
  11.     iMyList.remove(10);      //100 40 30 20 0 1 2 3 4 5 6 7 8 9  
  12.     iMyList.remove(8);       //100 40 30 20 0 1 2 3 4 5 6 7 9  
  13.   
  14.     cout << "------------ MyList ------------" << endl;  
  15.     for (ListIterator<int> iter(iMyList);  
  16.             !(iter.isEmpty());  
  17.             ++ iter)  
  18.         cout << *iter << ' ';  
  19.     cout << endl;  
  20.     cout << "Test: \n\t" << iMyList << endl;  
  21.   
  22.     return 0;  
  23. }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章