链表的基本操作

2013-08-17 16:26:51

再次写链表的基本操作,包括前插法创建链表、链表的插入、删除、排序、翻转、显示、销毁。

此次写的链表时带有头指针的,是否有头指针,对于链表的各个操作都会有影响,与之前写的不带头指针的链表相比,确实方便很多,不易出错。

小结:

  1. 对于带有头结点的链表,空链表(pHead->next= NULL)与头指针为NULL的链表(pHead = NULL)是不同的,后者是非法的链表,要当做异常处理;
  2. 函数入口对于异常输入的处理,比如下面代码中多个函数中的assert(pHead != NULL);排除了链表头结点为空的异常情况;
  3. 函数对于特殊输入的处理,比如插入、删除的位置大于链表长度,以及链表为空的处理;链表翻转时链表长度为空或1时直接返回即可;在函数开始时最好就对这些特殊的输入进行处理,以免遗漏;注意插入、删除的是第一个以及最后一个的情况
  4. 存放插入、删除的位置、链表长度的变量为size_t类型的,排除了非法的负数的情况,但也要注意这种做法带来的副作用,就是对于size_t类型的变量0-1的结果为最大的正数,而非负数,判断循环结束时,应注意到这个问题。
  5. 输入ctrl+z结束键盘输入后,要想再次从键盘接收输入,必须用cin.clear();  cin.sync();清楚流,否则不能接收输入

 

下面是完整的代码(包括测试):

  1 #include <iostream>
  2 #include <cassert>
  3 using namespace std;
  4 
  5 typedef int DataType;  //链表元素类型
  6 
  7 typedef struct node    //链表结点
  8 {
  9     DataType data;
 10     node *next;
 11 
 12 }LNode,*PLNode;
 13 
 14 //创建带有头结点的链表
 15 //输入ctrl+z结束
 16 //有无头结点将会影响到对链表的所有操作,包括显示链表元素、插入、删除、销毁等
 17 PLNode CreatLink()
 18 {
 19     PLNode pHead = new LNode;  //注意delete
 20     PLNode pPre = pHead;
 21     PLNode pCur = NULL;
 22     pHead->data = 0;        //空头
 23     pHead->next = pCur;
 24 
 25     DataType dataTmp = 0;
 26 
 27     cout<<"Please enter the elements of the link  ,separate with space,and end with ctrl+z :"<<endl;
 28     while (cin>>dataTmp)
 29     {
 30         pCur = new LNode;
 31         pCur->data = dataTmp;
 32         pCur->next = NULL;
 33 
 34         pPre->next = pCur;
 35         pPre = pCur;
 36     }
 37 
 38     return pHead;
 39 }
 40 
 41 //创建不带头结点的链表
 42 //输入ctrl+z结束
 43 PLNode CreatLinkWithNonNullHead()
 44 {
 45     PLNode pHead = NULL;  //delete
 46     PLNode pPre = NULL;
 47     PLNode pCur = NULL;
 48     
 49     DataType dataTmp = 0;
 50 
 51     cout<<"Please enter the elements of the link  ,separate with space,and end with ctrl+z :"<<endl;
 52     while (cin>>dataTmp)
 53     {
 54         pCur = new LNode;
 55         pCur->data = dataTmp;
 56         pCur->next = NULL;
 57 
 58         if (NULL == pHead)   //对头的特别处理
 59         {
 60             pHead = pCur;
 61             pPre = pCur;
 62         }
 63         else
 64         {
 65             pPre->next = pCur;
 66         }
 67         pPre = pCur;
 68     }
 69     return pHead;
 70 }
 71 
 72 //对头结点为pHead的链表,在位置posToInsert处插入元素dataToInsert
 73 //posToInsert定义为size_t类型,排除了位置为负数的异常输入
 74 //注意对输入位置超过链表长度的处理
 75 PLNode InsertLink(PLNode &pHead,size_t posToInsert,const DataType dataToInsert)
 76 {
 77     assert(pHead != NULL);
 78 
 79     PLNode pCur = pHead;
 80     PLNode pNew = new LNode;
 81     pNew->data = dataToInsert;
 82     pNew->next = NULL;
 83 
 84     while (posToInsert--)
 85     {
 86         //assert(pCur != NULL);  //保证不超过链表长度
 87         pCur = pCur->next;
 88         assert(pCur != NULL);  //保证不超过链表长度,放在前面当posToInsert减到0时会出错
 89     }
 90 
 91     pNew->next = pCur->next;
 92     pCur->next = pNew;
 93 
 94     return pHead;
 95 }
 96 
 97 //删除结点指针指向的元素,未测试
 98 PLNode InsertLinkAtNode(PLNode &pHead,const PLNode pPosToInsert,const DataType dataToInsert)
 99 {
100     assert(pHead != NULL);
101 
102     PLNode pCur = pHead;
103     PLNode pNew = new LNode;
104     pNew->data = dataToInsert;
105     pNew->next = NULL;
106 
107     while (pCur != pPosToInsert)
108     {
109         assert(pCur != NULL);  //保证不超过链表长度
110         pCur = pCur->next;
111     }
112 
113     pNew->next = pCur->next;
114     pCur->next = pNew;
115 
116     return pHead;
117 }
118 
119 //对头结点为pHead的链表,在位置posToInsert处插入元素dataToInsert
120 //posToInsert定义为size_t类型,排除了位置为负数的异常输入
121 //注意对输入位置超过链表长度的处理
122 PLNode DeleteLink(PLNode &pHead,size_t posToDelete)
123 {
124     assert(pHead != NULL);
125 
126     if (0 == posToDelete)
127     {
128         return pHead;
129     }
130 
131     PLNode pCur = pHead;
132     PLNode pNodeToDelete = NULL;
133     size_t posPriorToDelete = posToDelete - 1;
134 
135     while (posPriorToDelete--)
136     {
137         pCur = pCur->next;
138         assert(pCur != NULL);  //保证不超过链表长度,放在前面当posToInsert减到0时会出错
139     }
140 
141     pNodeToDelete = pCur->next;
142     assert(pNodeToDelete != NULL);  ////保证不超过链表长度
143     pCur->next = pNodeToDelete->next;
144     delete pNodeToDelete;
145     return pHead;
146 }
147 
148 //获取链表长度
149 size_t GetLengthOfLink(PLNode pHead)
150 {
151     assert(NULL != pHead);
152 
153     size_t lengthOfLink = 0;
154     PLNode pCur = pHead;
155 
156     while (NULL != pCur->next)
157     {
158         ++lengthOfLink;
159         pCur = pCur->next;
160     }
161 
162     return lengthOfLink;
163 }
164 
165 //冒泡法最链表元素排序
166 PLNode BubbleSortLink(PLNode &pHead)
167 {
168     assert(NULL != pHead);
169     
170     PLNode pCur = pHead->next;
171     
172     size_t lengthOfLink = GetLengthOfLink(pHead);  
173     size_t tmp = 0;
174     int i = (int)lengthOfLink; //定义为int型,在lengthOfLink为0时,lengthOfLink--为-1
175     int j = 0;
176 
177     while (i-- > 1)
178     {
179         pCur = pHead->next;  //每次都指向第一个结点
180         j = i;
181         /*while (j--)*/
182         while (j-- > 0)
183         {
184             if (pCur->data > pCur->next->data)
185             {
186                 tmp = pCur->data;
187                 pCur->data = pCur->next->data;
188                 pCur->next->data = tmp;
189             }
190 
191             pCur = pCur->next;
192         }
193     }
194     return pHead;
195 }
196 
197 //链表元素翻转
198 PLNode ReverseLink(PLNode &pHead)
199 {
200     assert(NULL != pHead);
201 
202     if (NULL == pHead->next || NULL == pHead->next->next)  //短路求值的特性保证pHead->next->next不会因为pHead->next == NULL而非法操作
203     {
204         return pHead;
205     }
206     
207     PLNode pPre = pHead->next;  //上面的if保证此处的访问都是合法的
208     PLNode pCur = pPre->next;
209     PLNode pNxt = NULL;
210 
211     pPre->next = NULL;  //此时pPre为翻转后链表的最后一个结点,将next置为NULL
212 
213     while (pCur != NULL)
214     {
215         pNxt = pCur->next;
216         pCur->next = pPre;  //指正方向翻转
217 
218         pPre = pCur;
219         pCur = pNxt;
220     }
221 
222     //pHead = pPre;
223     pHead->next = pPre;
224     return pHead;
225 }
226 
227 //显示有头结点的链表的元素
228 void Displaylink(const PLNode &pHead)
229 {
230     assert(pHead != NULL);
231     PLNode pCur = pHead->next;
232     while (pCur != NULL)
233     {
234         cout<<pCur->data<<"\t";
235         pCur = pCur->next;
236     }
237     cout<<endl;
238 }
239 
240 //显示没有头结点的链表的元素
241 void DisplaylinkWithNonNullHead(const PLNode &pHead)
242 {
243     PLNode pCur = pHead;
244     while (pCur != NULL)
245     {
246         cout<<pCur->data<<"\t";
247         pCur = pCur->next;
248     }
249     cout<<endl;
250 }
251 
252 //带有头结点的链表的销毁
253 void Destorylink(PLNode &pHead)
254 {
255     assert(pHead != NULL);
256     PLNode pCur = pHead->next;
257     while (pCur != NULL)
258     {
259         delete pHead;    //删除头结点
260         pHead = pCur;
261         pCur = pCur->next;
262     }
263 }
264 
265 //测试链表操作
266 //除了作为比较的建立链表操作,链表的所有操作都基于带有头结点的链表
267 //因为带有头结点的链表在各种操作上都会比较方便
268 void Testlink()
269 {
270     PLNode pHead = NULL;
271 
272     //Test CreatLinkWithNullHead...
273     cout<<"Test CreatLink..."<<endl;
274     pHead = CreatLink();
275     cout<<"display the link created by CreatLink : "<<endl;
276     Displaylink(pHead);
277     
278     cin.clear();  //清除流状态
279     cin.sync();
280 
281     //Test InsertLink...
282     /*size_t posToInsert = 0;
283     DataType dataToInsert = 0;
284 
285     cout<<"Please enter the position and the data to insert,end with ctrl+z :"<<endl;
286     while (cin>>posToInsert>>dataToInsert)
287     {
288         cout<<"The link before insertion : "<<endl;
289         Displaylink(pHead);
290 
291         pHead = InsertLink(pHead,posToInsert,dataToInsert);
292 
293         cout<<"The link after insertion : "<<endl;
294         Displaylink(pHead);
295 
296         cout<<"Please enter the position to insert,end with ctrl+z :"<<endl;
297     }
298     cin.clear();  //清除流状态
299     cin.sync();*/
300 
301     //Test DeleteLink...
302     //size_t posToDelete = 0;
303     //
304     //cout<<"Please enter the position to delete,end with ctrl+z :"<<endl;
305     //while (cin>>posToDelete)
306     //{
307     //    cout<<"The link before insertion : "<<endl;
308     //    Displaylink(pHead);
309 
310     //    pHead = DeleteLink(pHead,posToDelete);
311 
312     //    cout<<"The link after delete : "<<endl;
313     //    Displaylink(pHead);
314 
315     //    cout<<"Please enter the position to delete,end with ctrl+z :"<<endl;
316     //}
317 
318     //cin.clear();  //清除流状态
319     //cin.sync();
320 
321     //Test GetLengthOfLink...
322 
323     //size_t lengthOfLink = GetLengthOfLink(pHead);
324     cout<<"Test GetLengthOfLink..."<<endl;
325     cout<<"the length of link is : "<<GetLengthOfLink(pHead)<<endl;
326 
327     //Test BubbleSortLink...
328     cout<<"Test BubbleSortLink..."<<endl;
329     BubbleSortLink(pHead);
330     cout<<"The link after sort : "<<endl;
331     Displaylink(pHead);
332 
333     //Test BubbleSortLink...
334     cout<<"Test ReverseLink..."<<endl;
335     ReverseLink(pHead);
336     cout<<"The link after reverse : "<<endl;
337     Displaylink(pHead);
338 
339     Destorylink(pHead);
340 
341     /*cout<<"Test CreatLinkWithNonNullHead..."<<endl;
342     pHead = CreatLinkWithNonNullHead();
343     cout<<"display the link created by CreatLinkWithNullHead : "<<endl;
344     DisplaylinkWithNonNullHead(pHead);
345     Destorylink(pHead);*/
346 
347 }
348 
349 //main
350 int main()
351 {
352     Testlink();
353     return 0;
354 }

 

posted @ 2013-08-17 16:42  永不止步,永无止境  阅读(1219)  评论(0编辑  收藏  举报