代码改变世界

C语言 线性表 双向链式结构 实现

2013-10-28 17:55  wid  阅读(1073)  评论(0编辑  收藏  举报

一个双向链式结构实现的线性表 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 或程序缺陷, 请留言反馈, 谢谢。