问题:

如何遍历单链表中的每一个元素?

示例:

 

 在头部插入元素时,时间复杂度是O(n)。 获取元素时,时间复杂度是O(n*n),因为内层定位位置时有一个O(n)复杂度。

从理论上来说遍历一个单链表,只需要线性的时间就够了。

 

设计思路:

提供一组相关的遍历函数,遍历时使用这些函数来操作:

 

 

 

move函数的i参数为目标位置,step参数为每次移动的节点数。

end用来判断当前的游标是否到达了单链表的尾部。

current返回当前游标指向的数据元素。

next移动游标,移动的次数根据move中的step的值来决定。

遍历时,这四个函数必须配合使用才能得到最大效率。

 改进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 
 20     mutable struct : public Object
 21     {
 22         char reserved[sizeof(T)];
 23         Node* next;
 24     }m_header;
 25 
 26     int m_length;
 27     int m_step;
 28     Node* m_current;
 29 
 30     Node* position(int i) const    //  O(n)
 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 public:
 42     LinkList()
 43     {
 44         m_header.next = NULL;
 45         m_length = 0;
 46         m_step = 1;
 47         m_current = NULL;
 48     }
 49 
 50     bool insert(const T& e)
 51     {
 52         return insert(m_length, e);
 53     }
 54 
 55     bool insert(int i, const T& e)   // O(n)
 56     {
 57         bool ret = ((0 <= i) && (i <= m_length));
 58 
 59         if( ret )
 60         {
 61             Node* node = new Node();
 62 
 63             if( node != NULL )
 64             {
 65                 Node* current = position(i);
 66 
 67                 node->value = e;
 68                 node->next = current->next;
 69                 current->next = node;
 70 
 71                 m_length++;
 72             }
 73             else
 74             {
 75                 THROW_EXCEPTION(NoEnoughMemoryException, "No memery to insert new element...");
 76             }
 77         }
 78 
 79         return ret;
 80     }
 81 
 82     bool remove(int i)   // O(n)
 83     {
 84         bool ret = ((0 <= i) && (i < m_length));
 85 
 86         if( ret )
 87         {
 88             Node* current = position(i);
 89 
 90             Node* toDel = current->next;
 91 
 92             current->next = toDel->next;
 93 
 94             delete toDel;
 95 
 96             m_length--;
 97         }
 98 
 99         return ret;
100     }
101 
102     bool set(int i, const T& e)   //  O(n)
103     {
104         bool ret = ((0 <= i) && (i < m_length));
105 
106         if( ret )
107         {
108             position(i)->next->value = e;
109         }
110 
111         return ret;
112     }
113 
114     T get(int i) const
115     {
116         T ret;
117 
118         if( get(i, ret) )
119         {
120             return ret;
121         }
122         else
123         {
124             THROW_EXCEPTION(IndexOutOfBoundsException, "Invalid parameter i to get element ...");
125         }
126 
127         return ret;
128     }
129 
130     bool get(int i, T& e) const    // O(n)
131     {
132         bool ret = ((0 <= i) && (i < m_length));
133 
134         if( ret )
135         {
136             e = position(i)->next->value;
137         }
138 
139         return ret;
140     }
141 
142     int find(const T& e) const    //  O(n)
143     {
144         int ret = -1;
145         int i = 0;
146 
147         Node* node = m_header.next;
148 
149         while( node )
150         {
151             if( node->value == e )
152             {
153                 ret = i;
154                 break;
155             }
156             else
157             {
158                 node = node->next;
159                 i++;
160             }
161         }
162 
163         return ret;
164     }
165 
166     int length() const   // O(1)
167     {
168         return m_length;
169     }
170 
171     void clear()    //  O(n)
172     {
173         while( m_header.next )
174         {
175             Node* toDel = m_header.next;
176 
177             m_header.next = toDel->next;
178 
179             delete toDel;
180         }
181 
182         m_length = 0;
183     }
184 
185     bool move(int i, int step = 1)
186     {
187         bool ret = (0 <= i) && (i < m_length) && (step > 0);
188 
189         if( ret )
190         {
191             m_current = position(i)->next;
192             m_step = step;
193         }
194 
195         return ret;
196     }
197 
198     bool end()
199     {
200         return (m_current == NULL);
201     }
202 
203     T current()
204     {
205         if( !end() )
206         {
207             return m_current->value;
208         }
209         else
210         {
211             THROW_EXCEPTION(InvalidOperationException, "No value at current position ...");
212         }
213     }
214 
215     bool next()   //每次移动step步
216     {
217         int i = 0;
218 
219         while((i < m_step) && !end())
220         {
221             m_current = m_current->next;
222             i++;
223         }
224 
225         return (i == m_step);
226     }
227 
228     ~LinkList()   //  O(n)
229     {
230         clear();
231     }
232 };
233 
234 }
235 
236 #endif // LINKLIST_H

第27、28行我们添加了两个成员变量,第185-226行添加了遍历需要的函数。

测试程序如下:

 1 #include <iostream>
 2 #include "LinkList.h"
 3 
 4 
 5 using namespace std;
 6 using namespace DTLib;
 7 
 8 
 9 int main()
10 {
11     LinkList<int> list;
12 
13     for(int i = 0; i<5; i++)
14     {
15         list.insert(0,i);
16     }
17 
18     //遍历时必须先调用move函数
19     for(list.move(0); !list.end(); list.next())
20     {
21         cout << list.current() << endl;
22     }
23 
24     return 0;
25 }

遍历list时必须先调用move函数,指定位置和步进值step,step是给next函数用的,例如:step为5,则每次调用next函数就会向后移动5个元素。

结果如下:

这时的遍历操作时间复杂度是O(n)。

步进值为2时,结果如下:

 

 

单链表内部封装:

 

程序改进:

  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 
 20     mutable struct : public Object
 21     {
 22         char reserved[sizeof(T)];
 23         Node* next;
 24     }m_header;
 25 
 26     int m_length;
 27     int m_step;
 28     Node* m_current;
 29 
 30     Node* position(int i) const    //  O(n)
 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 
 47     virtual void destroy(Node* pn)
 48     {
 49         delete pn;
 50     }
 51 
 52 public:
 53     LinkList()
 54     {
 55         m_header.next = NULL;
 56         m_length = 0;
 57         m_step = 1;
 58         m_current = NULL;
 59     }
 60 
 61     bool insert(const T& e)
 62     {
 63         return insert(m_length, e);
 64     }
 65 
 66     bool insert(int i, const T& e)   // O(n)
 67     {
 68         bool ret = ((0 <= i) && (i <= m_length));
 69 
 70         if( ret )
 71         {
 72             Node* node = create();
 73 
 74             if( node != NULL )
 75             {
 76                 Node* current = position(i);
 77 
 78                 node->value = e;
 79                 node->next = current->next;
 80                 current->next = node;
 81 
 82                 m_length++;
 83             }
 84             else
 85             {
 86                 THROW_EXCEPTION(NoEnoughMemoryException, "No memery to insert new element...");
 87             }
 88         }
 89 
 90         return ret;
 91     }
 92 
 93     bool remove(int i)   // O(n)
 94     {
 95         bool ret = ((0 <= i) && (i < m_length));
 96 
 97         if( ret )
 98         {
 99             Node* current = position(i);
100 
101             Node* toDel = current->next;
102 
103             current->next = toDel->next;
104 
105             destroy(toDel);
106 
107             m_length--;
108         }
109 
110         return ret;
111     }
112 
113     bool set(int i, const T& e)   //  O(n)
114     {
115         bool ret = ((0 <= i) && (i < m_length));
116 
117         if( ret )
118         {
119             position(i)->next->value = e;
120         }
121 
122         return ret;
123     }
124 
125     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(IndexOutOfBoundsException, "Invalid parameter i to get element ...");
136         }
137 
138         return ret;
139     }
140 
141     bool get(int i, T& e) const    // O(n)
142     {
143         bool ret = ((0 <= i) && (i < m_length));
144 
145         if( ret )
146         {
147             e = position(i)->next->value;
148         }
149 
150         return ret;
151     }
152 
153     int find(const T& e) const    //  O(n)
154     {
155         int ret = -1;
156         int i = 0;
157 
158         Node* node = m_header.next;
159 
160         while( node )
161         {
162             if( node->value == e )
163             {
164                 ret = i;
165                 break;
166             }
167             else
168             {
169                 node = node->next;
170                 i++;
171             }
172         }
173 
174         return ret;
175     }
176 
177     int length() const   // O(1)
178     {
179         return m_length;
180     }
181 
182     void clear()    //  O(n)
183     {
184         while( m_header.next )
185         {
186             Node* toDel = m_header.next;
187 
188             m_header.next = toDel->next;
189 
190             destroy(toDel);
191         }
192 
193         m_length = 0;
194     }
195 
196     bool move(int i, int step = 1)
197     {
198         bool ret = (0 <= i) && (i < m_length) && (step > 0);
199 
200         if( ret )
201         {
202             m_current = position(i)->next;
203             m_step = step;
204         }
205 
206         return ret;
207     }
208 
209     bool end()
210     {
211         return (m_current == NULL);
212     }
213 
214     T current()
215     {
216         if( !end() )
217         {
218             return m_current->value;
219         }
220         else
221         {
222             THROW_EXCEPTION(InvalidOperationException, "No value at current position ...");
223         }
224     }
225 
226     bool next()   //每次移动step步
227     {
228         int i = 0;
229 
230         while((i < m_step) && !end())
231         {
232             m_current = m_current->next;
233             i++;
234         }
235 
236         return (i == m_step);
237     }
238 
239     ~LinkList()   //  O(n)
240     {
241         clear();
242     }
243 };
244 
245 }
246 
247 #endif // LINKLIST_H

调用new生成Node的地方我们全换成了create函数,调用delete销毁Node的地方我们全换成了destroy函数。

问题:

封装这两个函数的意义是什么?

 

小结:

 

posted on 2018-09-15 13:28  周伯通789  阅读(420)  评论(0编辑  收藏  举报