第三十课 双向链表的实现

 由上图可以看出来,插入和遍历的时间复杂度是不一样的。

这样不管游标在哪一个位置上,都可以通过后继或者前驱指针任意访问。

双向链表的继承层次:

 单链表和双向链表应该是兄弟关系,而不应该是继承关系,因为它们的内部机制是完全不同的了。

 插入新节点图解:

删除节点的步骤:

添加DualLinkList.h文件:

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

和LinkList的不同只在于Node的元素,我们新添加了pre成员。

insert函数和remove函数是改动最大的。

新增加了pre函数。

测试程序如下:

 1 #include <iostream>
 2 #include "DualLinkList.h"
 3 
 4 using namespace std;
 5 using namespace DTLib;
 6 
 7 
 8 int main()
 9 {
10     DualLinkList<int> dl;
11 
12     for(int i = 0; i < 5; i++)
13     {
14         dl.insert(0, i);
15     }
16 
17     for(int i = 0; i < dl.length(); i++)
18     {
19         cout << dl.get(i) << endl;
20     }
21 
22     cout << "begin" << endl;
23 
24     for(dl.move(dl.length() - 1); !dl.end(); dl.pre())
25     {
26         cout << dl.current() << endl;
27     }
28 
29     cout << "end" << endl;
30 
31     return 0;
32 }

第一个for循环时间复杂度是O(n*n),第二个for循环的时间复杂度是O(n)。

结果如下:

测试程序2:

 1 #include <iostream>
 2 #include "DualLinkList.h"
 3 
 4 using namespace std;
 5 using namespace DTLib;
 6 
 7 
 8 int main()
 9 {
10     DualLinkList<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     for(dl.move(0); !dl.end(); dl.next())
19     {
20         cout << dl.current() << endl;
21     }
22 
23     cout << "begin" << endl;
24 
25     dl.move(dl.length() - 1);
26 
27     while(!dl.end())
28     {
29         if( dl.current() == 5 )
30         {
31             cout << dl.current() << endl;
32 
33             dl.remove(dl.find(dl.current()));
34         }
35         else
36         {
37             dl.pre();
38         }
39     }
40 
41     cout << "end" << endl;
42 
43     for(dl.move(0); !dl.end(); dl.next())
44     {
45         cout << dl.current() << endl;
46     }
47 
48     return 0;
49 }

结果如下:

小结:

 

 双向链表的子类:

原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9655599.html