第三十三课 双向循环链表的实现

头结点不位于链表里面,只是用于定位,和内核链表不同。

 

将LinuxList.h添加到我们的工程中。

再添加一个DualCircleList.h文件:

  1 #ifndef DUALCIRCLELIST_H
  2 #define DUALCIRCLELIST_H
  3 
  4 #include "LinuxList.h"
  5 #include "DualLinkList.h"
  6 
  7 namespace DTLib
  8 {
  9 
 10 template < typename T >
 11 class DualCircleList : public DualLinkList<T>
 12 {
 13 protected:
 14     struct Node : public Object
 15     {
 16         list_head head;
 17         T value;
 18     };
 19 
 20     list_head m_header;
 21     list_head* m_current;
 22 
 23     list_head* position(int i) const
 24     {
 25         list_head* ret = const_cast<list_head*>(&m_header); //这里需要进行const_cast转换,否则无法在const函数里面取m_header的地址
 26 
 27         for(int p=0; p<i; p++)
 28         {
 29             ret = ret->next;
 30         }
 31 
 32         return ret;
 33     }
 34 
 35     int mod(int i) const
 36     {
 37         return (this->m_length == 0) ? 0 : (i % this->m_length);;
 38     }
 39 
 40 public:
 41     DualCircleList()
 42     {
 43         this->m_length = 0;
 44         this->m_step = 1;
 45 
 46         m_current = NULL;
 47 
 48         INIT_LIST_HEAD(&m_header);
 49     }
 50 
 51     bool insert(const T& e)
 52     {
 53         return insert(this->m_length, e);
 54     }
 55 
 56     bool insert(int i, const T& e)
 57     {
 58         bool ret = true;
 59         Node* node = new Node();
 60 
 61         i = i % (this->m_length + 1);
 62 
 63         if(node != NULL)
 64         {
 65             node->value = e;
 66 
 67             list_add_tail(&node->head, position(i)->next);
 68 
 69             this->m_length++;
 70         }
 71         else
 72         {
 73             THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create Node object ...");
 74         }
 75 
 76         return ret;
 77     }
 78 
 79     bool remove(int i)
 80     {
 81         bool ret = true;
 82 
 83         i = mod(i);
 84 
 85         ret = ((0 <= i) &&(i<this->m_length));
 86 
 87         if( ret )
 88         {
 89             list_head* toDel = position(i)->next;
 90 
 91             if( m_current == toDel )
 92             {
 93                 m_current = toDel->next;
 94             }
 95 
 96             list_del(toDel);
 97 
 98             this->m_length--;
 99 
100             delete list_entry(toDel, Node, head);
101         }
102 
103         return ret;
104     }
105 
106     bool set(int i, const T& e)   //  O(n)
107     {
108         bool ret = true;
109         i = mod(i);
110         ret = ((0 <= i) && (i < this->m_length));
111 
112         if( ret )
113         {
114             list_entry(position(i)->next, Node, head)->value = e;
115         }
116 
117         return ret;
118     }
119 
120     virtual T get(int i) const   // O(n)
121     {
122         T ret;
123 
124         if( get(i, ret) )
125         {
126             return ret;
127         }
128         else
129         {
130             THROW_EXCEPTION(IndexOutOfBoundsException, "Invalid parameter i to get element ...");
131         }
132 
133         return ret;
134     }
135 
136     bool get(int i, T& e) const    // O(n)
137     {
138         bool ret = true;
139 
140         i = mod(i);
141 
142         ret = ((0 <= i) && (i < this->m_length));
143 
144         if( ret )
145         {
146             e = list_entry(position(i)->next, Node, head)->value;
147         }
148 
149         return ret;
150     }
151 
152     int find(const T& e) const
153     {
154         int ret = -1;
155 
156         int i = 0;
157 
158         list_head* slider = NULL;
159 
160         list_for_each(slider, &m_header)
161         {
162             if( list_entry(slider, Node, head )->value == e)
163             {
164                 ret = i;
165                 break;
166             }
167 
168             i++;
169         }
170 
171         return ret;
172     }
173 
174     int length() const
175     {
176         return this->m_length;
177     }
178 
179     void clear()
180     {
181         while( this->m_length > 0 )
182         {
183             remove(0);
184         }
185     }
186 
187     bool move(int i, int step = 1)
188     {
189         bool ret = (step > 0);
190 
191         i = mod(i);
192 
193         ret = ret && ((0 <= i) && (i < this->m_length));
194 
195         if( ret )
196         {
197             m_current = position(i)->next;
198 
199             this->m_step = step;
200         }
201 
202         return ret;
203     }
204 
205     bool end()
206     {
207         return (m_current == NULL) || (this->m_length == 0);
208     }
209 
210     T current()
211     {
212         if( !end() )
213         {
214             return list_entry(m_current, Node, head)->value;
215         }
216         else
217         {
218             THROW_EXCEPTION(InvalidOperationException, "No value at current position ...");
219         }
220     }
221 
222     bool next()
223     {
224         int i = 0;
225 
226         while((i < this->m_step) && !end())
227         {
228             if( m_current != &m_header )
229             {
230                 m_current = m_current->next;
231                 i++;
232             }
233             else
234             {
235                 m_current = m_current->next;
236             }
237         }
238 
239         if( m_current == &m_header )
240         {
241             m_current = m_current->next;
242         }
243 
244         return (i == this->m_step);
245     }
246 
247     bool pre()
248     {
249         int i = 0;
250 
251         while((i < this->m_step) && !end())
252         {
253             if( m_current != &m_header )
254             {
255                 m_current = m_current->prev;
256                 i++;
257             }
258             else
259             {
260                 m_current = m_current->prev;
261             }
262         }
263 
264         if( m_current == &m_header )
265         {
266             m_current = m_current->prev;
267         }
268 
269         return (i == this->m_step);
270     }
271 
272     ~DualCircleList()
273     {
274         clear();
275     }
276 };
277 
278 }
279 
280 #endif // DUALCIRCLELIST_H

 我们的实现中,头结点只为了做定位用,不属于链表中的一个元素,因此,next和pre函数要跳过头结点。

单向循环链表CircleList是继承的LinkList的next函数,只向一个方向移动,而且不会越过头结点。

测试程序如下:

 1 #include <iostream>
 2 #include "DualCircleList.h"
 3 
 4 using namespace std;
 5 using namespace DTLib;
 6 
 7 
 8 int main()
 9 {
10     DualCircleList<int> dl;
11 
12     for(int i = 0; i < 5; i++)
13     {
14         dl.insert(0, i);
15         dl.insert(0, 5);
16     }
17 
18     cout << "begin" << endl;
19 
20     dl.move(dl.length() - 1);
21 
22     while(dl.find(5) != -1)   //所有的5全部被删除后停止循环
23     {
24         if( dl.current() == 5 )
25         {
26             cout << dl.current() << endl;
27 
28             dl.remove(dl.find(dl.current()));
29         }
30         else
31         {
32             dl.pre();
33         }
34     }
35 
36     cout << "end" << endl;
37 
38     for(int i = 0; i < dl.length(); i++)
39     {
40         cout << dl.get(i) << endl;
41     }
42 
43     return 0;
44 }

运行结果如下:

使用以下程序访问会得到死循环:

 因为当前是一个双向循环链表。

小结:

思考题:

猜你喜欢

转载自www.cnblogs.com/wanmeishenghuo/p/9656853.html