C語言 線性表 雙向鏈式結構 實現

一個雙向鏈式結構實現的線性表 duList (GCC編譯)。函數

  1 /**
  2 * @brief 線性表雙向鏈表結構
  3 * @author wid
  4 * @date 2013-10-28
  5 *
  6 * @note 若代碼存在 bug 或程序缺陷, 請留言反饋, 謝謝!
  7 */
  8 
  9 #include <stdio.h>
 10 #include <stdlib.h>
 11 
 12 #define TRUE 1
 13 #define FALSE 0
 14 
 15 typedef struct Point2D
 16 {
 17     int x;
 18     int y;
 19 }ElemType;      //數據元素結構
 20 
 21 typedef struct DUNODE
 22 {
 23     ElemType pt;            //數據元素
 24     struct DUNODE *next;     //後繼節點
 25     struct DUNODE *prior;    //前驅節點
 26 }duNode;        //節點結構
 27 
 28 typedef struct DULIST
 29 {
 30     duNode *head;           //頭結點
 31     duNode *foot;           //尾節點
 32     int len;                //鏈表長度
 33 }duList;        //鏈表結構
 34 
 35 
 36 // duList 方法聲明
 37 duNode *MakeNode();         ///產生一個節點
 38 duList *CreateList();       ///生成一條空雙向線性表
 39 void DestroyList( duList *pList );                  ///銷燬線性表
 40 void ClearList( duList *pList );                    ///置空線性表
 41 int GetLength( duList *pList );                     ///獲取線性表長度
 42 int IsEmpty( duList *pList );                       ///檢測線性表是否爲空
 43 int AppendElem( duList *pList, ElemType *pt );      ///向線性表末尾添加數據元素
 44 int InsertElem( duList *pList, int nPos, ElemType *pt );      ///向線性中插入數據元素
 45 int DeleteElem( duList *pList, int nPos );          ///從線性中刪除數據元素
 46 int GetElem( duList *pList, int nPos, ElemType *pt );         ///獲取線性表中某位置上的元素
 47 int FindElem( duList *pList, int nPos, ElemType *pt );        ///從某位置起查找某元素在線性表中第一次出現的位置
 48 int GetPriorElem( duList *pList, ElemType *pt, ElemType *prior_pt );     ///從線性表中獲取 pt 的前驅節點到 prior_pt
 49 int GetNextElem( duList *pList, ElemType *pt, ElemType *next_pt );       ///從線性表中獲取 pt 的後繼節點到 next_pt
 50 void ForEachList( duList *pList, void (*func)(ElemType *pt) );           ///對線性表中每一個元素從前向後依次執行 func 函數
 51 void ReForEachList( duList *pList, void (*func)(ElemType *pt) );         ///對線性表中每一個元素從後向前依次執行 func 函數
 52 int ListCpy( duList *pDestList, duList *pSrcList );           ///將一線性表複製到另外一線性表後
 53 int ListCat( duList *pDestList, duList *pSrcList );           ///將一線性錶鏈接到另外一線性表後
 54 
 55 
 56 // duList 方法實現
 57 
 58 /**
 59 * @brief 生成一個鏈表節點
 60 *
 61 * @return 指向生成的節點的指針
 62 */
 63 duNode *MakeNode()
 64 {
 65     duNode *pNode = (duNode *)malloc( sizeof(duNode) );
 66     pNode->next = NULL;
 67     pNode->prior = NULL;
 68 
 69     return pNode;
 70 }
 71 
 72 /**
 73 * @brief 建立一個空的雙向線性表
 74 *
 75 * @return 返回指向生成的線性表的指針
 76 */
 77 duList *CreateList()
 78 {
 79     duList *pList = (duList *)malloc( sizeof(duList) );
 80     pList->head = pList->foot = MakeNode();
 81     pList->head->next = NULL;
 82     pList->foot->prior = NULL;
 83 
 84     pList->len = 0;
 85 
 86     return pList;
 87 }
 88 
 89 /**
 90 * @brief 銷燬一條線性表
 91 *
 92 * @param 指向待銷燬的線性表的指針
 93 *
 94 * @return void
 95 */
 96 void DestroyList( duList *pList )
 97 {
 98     duNode *pm = pList->head, *pn = NULL;
 99 
100     while( pm != NULL )
101     {
102         pn = pm->next;
103         free(pm);
104         pm = pn;
105     }
106 
107     free( pList );
108     pList = NULL;
109 }
110 
111 /**
112 * @brief 置空一條線性表
113 *
114 * @param pList 指向待置空的線性表指針
115 *
116 * @return void
117 */
118 void ClearList( duList *pList )
119 {
120     duNode *pm = pList->head->next, *pn = NULL;
121     while( pm != NULL )
122     {
123         pn = pm->next;
124         free(pm);
125         pm = pn;
126     }
127 
128     pList->foot = pList->head;
129     pList->head->next = NULL;
130     pList->foot->prior = NULL;
131     pList->len = 0;
132 }
133 
134 /**
135 * @brief 獲取線性表長度
136 *
137 * @param pList 指向待獲取長度的線性表指針
138 *
139 * @return 返回線性表長度
140 */
141 int GetLength( duList *pList )
142 {
143     return pList->len;
144 }
145 
146 /**
147 * @brief 檢測線性表是否爲空
148 *
149 * @param pList 指向待檢測的線性表指針
150 *
151 * @return 爲空返回 TRUE, 不然返回 FALSE
152 */
153 int IsEmpty( duList *pList )
154 {
155     return pList->len == 0 ? TRUE : FALSE;
156 }
157 
158 /**
159 * @brief 向線性表末尾添加數據元素
160 *
161 * @param pList 指向待添加數據元素的線性表指針
162 * @param pt 指向數據元素的指針
163 *
164 * @return 返回成功添加後的線性表長度
165 */
166 int AppendElem( duList *pList, ElemType *pt )
167 {
168     duNode *pNode = MakeNode();
169     pNode->pt.x = pt->x;
170     pNode->pt.y = pt->y;
171 
172     pList->foot->next = pNode;
173     pNode->next = NULL;
174     pNode->prior = pList->foot;
175     pList->foot = pNode;
176 
177     return ++pList->len;
178 }
179 
180 /**
181 * @brief 向線性表中插入數據元素
182 *
183 * @param nPos 元素插入的位置
184 * @param pt 指向待插入的數據元素的指針
185 *
186 * @return 插入成功則返回成功插入後線性表的長度, 不然返回 -1
187 *
188 * @note 元素位置由0計起
189 */
190 int InsertElem( duList *pList, int nPos, ElemType *pt )
191 {
192     ///要插入的位置不在線性表中
193     if( nPos < 0 || nPos > pList->len )
194         return -1;
195 
196     duNode *pNode = MakeNode();
197     pNode->pt.x = pt->x;
198     pNode->pt.y = pt->y;
199 
200     duNode *pm = pList->head;
201 
202     if( nPos == pList->len )        ///插入到尾部, 特殊處理
203     {
204         pNode->next = NULL;
205         pNode->prior = pList->foot;
206         pList->foot->next = pNode;
207         pList->foot = pNode;
208 
209         return ++pList->len;
210     }
211 
212     int i = 0;
213     for( i = 0; i < nPos; ++i, pm = pm->next );
214     pNode->next = pm->next;
215     pNode->prior = pm;
216     pm->next->prior = pNode;
217     pm->next = pNode;
218 
219     return ++pList->len;
220 }
221 
222 /**
223 * @brief 從線性表中刪除一個節點元素
224 *
225 * @param pList 指向待刪除元素的線性表指針
226 * @param nPos 須要刪除的元素位置
227 *
228 * @return 成功刪除後返回刪除後線性表的長度, 不然返回-1
229 */
230 int DeleteElem( duList *pList, int nPos )
231 {
232     ///須要刪除的節點不在線性表中
233     if( nPos < 0 || nPos > pList->len-1 )
234         return -1;
235 
236     duNode *pm = pList->head, *pn = NULL;
237 
238     ///刪除尾節點, 特殊處理
239     if( nPos == pList->len-1 )
240     {
241         pn = pList->foot;
242         pList->foot = pList->foot->prior;
243         pList->foot->next = NULL;
244         free(pn);
245 
246         return --pList->len;
247     }
248 
249     int i = 0;
250     for( i = 0; i < nPos; ++i, pm = pm->next );
251 
252     pn = pm->next;
253     pm->next = pn->next;
254     pn->prior = pm;
255     free(pn);
256 
257     return --pList->len;
258 }
259 
260 /**
261 * @brief 獲取線性表中某位置上的元素
262 *
263 * @param pList 指向待獲取元素的線性表指針
264 * @param nPos 元素在線性表中的位置
265 * @param pt 指向存放獲取到的元素的指針
266 *
267 * @return 若獲取成功, 返回 TRUE, 不然返回 FALSE
268 *
269 * @note 元素位置從 0 計起
270 */
271 int GetElem( duList *pList, int nPos, ElemType *pt )
272 {
273     if( nPos < 0 || nPos > pList->len-1 )
274         return FALSE;
275 
276     duNode *p = NULL;
277     int i = 0;
278     ///判斷從哪端起獲取元素更近
279     if( pList->len / 2 > nPos )     //從首端取
280     {
281         p = pList->head;
282         for( i = 0; i <= nPos; ++i, p = p->next );
283     }
284     else    //從尾端取
285     {
286         nPos = pList->len - nPos - 1;
287         p = pList->foot;
288         for( i = 0; i < nPos; ++i, p = p->prior );
289     }
290 
291     pt->x = p->pt.x;
292     pt->y = p->pt.y;
293 
294     return TRUE;
295 }
296 
297 /**
298 * @brief 從某位置起查找某元素在線性表中第一次出現的位置
299 *
300 * @param pList 指向待查找元素的線性表的指針
301 * @param nPos 查找起始位置
302 * @param pt 指向待查找的元素的指針
303 *
304 * @return 若找到, 則返回元素所在的位置, 不然返回 -1
305 *
306 * @note 起始位置由 0 計起
307 */
308 int FindElem( duList *pList, int nPos, ElemType *pt )
309 {
310     ///起始位置不在線性表內
311     if( nPos < 0 || nPos > pList->len -1 )
312         return -1;
313 
314     duNode *p = pList->head;
315     int i = 0, ncnt = 0;
316 
317     for( i = 0; i < nPos; ++i, p = p->next );
318     while( p->next != NULL && (p = p->next) )
319     {
320         if( p->pt.x == pt->x && p->pt.y == pt->y )
321             return nPos + ncnt;
322 
323         ++ncnt;
324     }
325 
326     return -1;
327 }
328 
329 /**
330 * @brief 獲取某 pt 元素的前驅節點到 prior_pt
331 *
332 * @param pList 指向待獲取前驅節點的線性表指針
333 * @param pt 指向目標節點的指針
334 * @param prior_pt 存放目標節點 pt 的前驅節點
335 *
336 * @return 若成功獲取前驅節點, 返回該前驅節點在線性表中的位置, 不然返回 -1
337 *
338 * @note 元素位置從 0 計起
339 */
340 int GetPriorElem( duList *pList, ElemType *pt, ElemType *prior_pt )
341 {
342     duNode *p = pList->head;
343     int ncnt = 0;
344 
345     while( p != NULL && (p = p->next) )
346     {
347         if( p->pt.x == pt->x && p->pt.y == pt->y )
348         {
349             if( ncnt == 0 )     ///pt爲頭結點, 不存在前驅節點
350                 return -1;
351 
352             prior_pt->x = p->prior->pt.x;
353             prior_pt->y = p->prior->pt.y;
354 
355             return ncnt - 1;
356         }
357 
358         ++ncnt;
359     }
360 
361     return -1;
362 }
363 
364 /**
365 * @brief 獲取某 pt 元素的後繼節點到 next_pt
366 *
367 * @param pList 指向待獲取先後繼點的線性表指針
368 * @param pt 指向目標節點的指針
369 * @param prior_pt 存放目標節點 pt 的後繼節點
370 *
371 * @return 若成功獲取後繼節點, 返回該後繼節點在線性表中的位置, 不然返回 -1
372 *
373 * @note 元素位置從 0 計起
374 */
375 int GetNextElem( duList *pList, ElemType *pt, ElemType *next_pt )
376 {
377     duNode *p = pList->head;
378     int ncnt = 0;
379 
380     while( p != NULL && (p = p->next) )
381     {
382         if( p->pt.x == pt->x && p->pt.y == pt->y )
383         {
384             if( ncnt == pList->len-1 )    ///pt爲尾節點, 不存在後繼節點
385                 return -1;
386 
387             next_pt->x = p->next->pt.x;
388             next_pt->y = p->next->pt.y;
389 
390             return ncnt + 1;
391         }
392 
393         ++ncnt;
394     }
395 
396     return -1;
397 }
398 
399 /**
400 * @brief 對線性表中每一個元素從前向後依次執行 func 函數
401 *
402 * @param pList 指向待處理的線性表的指針
403 * @param func 傳入的函數指針
404 *
405 * @return void
406 */
407 void ForEachList( duList *pList, void (*func)(ElemType *pt) )
408 {
409     duNode *p = pList->head;
410     while( (p = p->next) != NULL )
411     {
412         func( &p->pt );
413     }
414 }
415 
416 /**
417 * @brief 對線性表中每一個元素從後向前依次執行 func 函數
418 *
419 * @param pList 指向待處理的線性表的指針
420 * @param func 傳入的函數指針
421 *
422 * @return void
423 */
424 void ReForEachList( duList *pList, void (*func)(ElemType *pt) )
425 {
426     duNode *p = pList->foot;
427     while( p->prior != NULL )
428     {
429         func( &p->pt );
430         p = p->prior;
431     }
432 }
433 
434  /**
435 * @brief 將 pSrcList 性表複製到 pDestList 線性表後
436 *
437 * @param pDestList 指向目標線性表指針
438 * @param pSrcList 指向源線性表指針
439 *
440 * @return 返回複製後目標線性表長度
441 */
442 int ListCpy( duList *pDestList, duList *pSrcList )
443 {
444     duNode *p = pSrcList->head, *tmp = NULL;
445     while( p->next != NULL && (p = p->next) )
446     {
447         tmp = MakeNode();
448         tmp->pt.x = p->pt.x;
449         tmp->pt.y = p->pt.y;
450 
451         tmp->prior = pDestList->foot;
452         pDestList->foot->next = tmp;
453         pDestList->foot = tmp;
454     }
455     pDestList->foot->next = NULL;
456     pDestList->len += pSrcList->len;
457 
458     return pDestList->len;
459 }
460 
461 /**
462 * @brief 將 pSrcList 性錶鏈接到 pDestList 線性表後
463 *
464 * @param pDestList 指向目標線性表指針
465 * @param pSrcList 指向源線性表指針
466 *
467 * @return 返回鏈接後目標線性表長度
468 *
469 * @note 鏈接後 pSrcList 線性表將被銷燬
470 */
471 int ListCat( duList *pDestList, duList *pSrcList )
472 {
473     pDestList->foot->next = pSrcList->head->next;
474     pSrcList->head->next->prior = pDestList->foot;
475     pDestList->foot = pSrcList->foot;
476     pDestList->len += pSrcList->len;
477 
478     free(pSrcList);
479     pSrcList = NULL;
480 
481     return pDestList->len;
482 }
483 
484 //測試 duList
485 
486 void display( ElemType *pt )
487 {
488     printf("(%d,%d) ", pt->x, pt->y);
489 }
490 
491 int main()
492 {
493     ///建立雙向線性表
494     duList *plA = CreateList();
495     duList *plB = CreateList();
496 
497     ElemType pt1, pt2;
498 
499     int i = 0, n = 0, pos = 0;
500 
501     ///向線性表中添加元素
502     for( i = 0; i < 6; ++i )
503     {
504         pt1.x = pt1.y = i;
505         AppendElem( plA, &pt1 );
506     }
507 
508     for( i = 0; i < 4; ++i )
509     {
510         pt2.x = pt2.y = i;
511         AppendElem( plB, &pt2 );
512     }
513 
514     ///測試 IsEmpty、GetLength
515     if( IsEmpty(plA) == FALSE )
516         printf( "plA length = %d\n", GetLength(plA) );
517 
518     ///測試 ForEachList、ReForEachList
519     ForEachList( plA, display );      //測試迭代輸出 plA 中元素
520     putchar( '\n' );
521     ReForEachList( plA, display );    //測試反向迭代輸出 plA 中元素
522 
523     printf( "\n\n" );
524     ///測試 InsertElem
525     pt1.x = pt1.y = 100;
526     puts("plA測試InsertElem"); InsertElem( plA, 0, &pt1 );       //在 plA 位置 0 處插入元素(1, 1)
527     ForEachList( plA, display );
528 
529     printf( "\n\n" );
530     ///測試 DeletetElem
531     puts("plA測試DeleteElem"); DeleteElem( plA, 1 );             //在 plA 位置 1 處的元素
532     ForEachList( plA, display );
533 
534     printf( "\n\n" );
535     ///測試 GetElem
536     GetElem( plA, 3, &pt2 );
537     printf( "plA 位置爲 3 的元素爲: (%d,%d)", pt2.x, pt2.y );
538 
539     printf( "\n\n" );
540     ///測試 GetPriorElem
541     GetPriorElem( plA, &pt2, &pt1 );
542     printf( "plA 位置爲 3 的元素(%d,%d)的前驅節點爲(%d,%d)", pt2.x, pt2.y, pt1.x, pt1.y );
543 
544     printf( "\n\n" );
545     ///測試 GetNextElem
546     GetNextElem( plA, &pt2, &pt1 );
547     printf( "plA 位置爲 3 的元素(%d,%d)的後繼節點爲(%d,%d)", pt2.x, pt2.y, pt1.x, pt1.y );
548 
549     printf( "\n\n" );
550     ///測試 FindElem
551     pt1.x = pt1.y = 5;
552     printf( "元素(5,5)在plA中的位置爲: %d", FindElem( plA, 0, &pt1 ) );
553 
554     printf( "\n\n" );
555     ///測試 ListCpy
556     puts( "測試ListCpy plB到PlA: " );
557     ListCpy( plA, plB );
558     ForEachList( plA, display );
559     printf( "\n複製後plA長度: %d", GetLength(plA) );
560 
561     printf( "\n\n" );
562     ///測試 ListCpy
563     puts( "測試ListCat plB到PlA: " );
564     ListCat( plA, plB );
565     ForEachList( plA, display );
566     printf( "\n鏈接後plA長度: %d", GetLength(plA) );
567 
568     DestroyList( plA );
569 
570     return 0;
571 }

若代碼存在 bug 或程序缺陷, 請留言反饋, 謝謝。                                                                                                                                                                                                                                                                                                                                                            測試

相關文章
相關標籤/搜索