代码改变世界

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

2013-10-22 20:10  wid  阅读(2007)  评论(7编辑  收藏  举报

一个单链式实现的线性表 mList (GCC编译)。

  1 /**
  2 * @brief 线性表的链式实现 (单链表)
  3 * @author wid
  4 * @date 2013-10-21
  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
 16 {
 17     int x;
 18     int y;
 19 }Point2D;   //Point2D 结构
 20 typedef Point2D ElemType;       //声明 Point2D 结构的别名 ElemType
 21 
 22 typedef struct LNode
 23 {
 24     Point2D pt;
 25     struct LNode *next;
 26 }ListNode;          //线性表数据项结构
 27 
 28 typedef struct
 29 {
 30     ListNode *head;     //数据项头节点
 31     int length;         //线性表长度
 32 }mList;         //线性表 mList 结构
 33 
 34 
 35 //线性表方法声明
 36 mList *CreateList();        ///创建一个空的线性表
 37 void DestroyList( mList *pList );   ///销毁一条线性表
 38 void ClearList( mList *pList );     ///置空一条线性表
 39 int GetLength( mList *pList );      ///获取线性表当前长度
 40 int IsEmpty( mList *pList );        ///检测线性表是否为空
 41 int AppendElem( mList *pList, ElemType *pt );            ///向线性表末尾添加一个元素
 42 int InsertElem( mList *pList, int nPos, ElemType *pt );  ///向线性表中插入一个元素
 43 int DeleteElem( mList *pList, int nPos );                ///从线性表中删除一个元素
 44 int GetElem( mList *pList, int nPos, ElemType *pt );     ///获取线性表中某位置上的元素
 45 int FindElem( mList *pList, int nPos, ElemType *pt );    ///从某位置起查找某元素在线性表中第一次出现的位置
 46 int GetPriorElem( mList *pList, ElemType *pt, ElemType *prior_pt );     ///从线性表中获取 pt 的前驱节点到 prior_pt
 47 int GetNextElem( mList *pList, ElemType *pt, ElemType *next_pt );       ///从线性表中获取 pt 的后继节点到 next_pt
 48 void ForEachList( mList *pList, void (*func)(ElemType *pt) );           ///对线性表中每个元素执行 func 函数
 49 int ListCpy( mList *pDestList, mList *pSrcList );        ///将一线性表复制到另一线性表后
 50 int ListCat( mList *pDestList, mList *pSrcList );        ///将一线性表连接到另一线性表后
 51 
 52 
 53 //线性表方法实现
 54 
 55 /**
 56 * @brief 创建一个空的线性表
 57 *
 58 * @return 指向创建的线性表的指针
 59 */
 60 mList *CreateList()
 61 {
 62     mList *pList = (mList *)malloc(sizeof(mList));
 63     pList->head = (ListNode *)malloc(sizeof(ListNode));
 64     pList->head->next = NULL;
 65     pList->length = 0;
 66 
 67     return pList;
 68 }
 69 
 70 /**
 71 * @brief 销毁一条线性表
 72 *
 73 * @param 指向待销毁的线性表的指针
 74 *
 75 * @return void
 76 */
 77 void DestroyList( mList *pList )
 78 {
 79     ListNode *pm = pList->head, *pn = NULL;
 80     while( pm != NULL )
 81     {
 82         pn = pm->next;
 83         free(pm);
 84         pm = pn;
 85     }
 86     free(pList);
 87     pList = NULL;
 88 }
 89 
 90 /**
 91 * @brief 置空一条线性表
 92 *
 93 * @param 指向待置空的线性表指针
 94 *
 95 * @return void
 96 */
 97 void ClearList( mList *pList )
 98 {
 99     ListNode *pm = pList->head, *pn = NULL;
100     while( pm != NULL )
101     {
102         pn = pm->next;
103         free(pm);
104         pm = pn;
105     }
106     pList->head->next = NULL;
107     pList->length = 0;
108 }
109 
110 /**
111 * @brief 获取线性表当前长度
112 *
113 * @param 指针待获取长度的线性表的指针
114 *
115 * @return 返回获取到的线性表长度
116 */
117 int GetLength( mList *pList )
118 {
119     return pList->length;
120 }
121 
122 /**
123 * @brief 检测线性表是否为空
124 *
125 * @param pList 指向待检测的线性表的指针
126 *
127 * @return 若为空则返回 TRUE, 否则返回 FALSE
128 */
129 int IsEmpty( mList *pList )
130 {
131     return pList->length == 0 ? TRUE : FALSE;
132 }
133 
134 /**
135 * @brief 向线性表末尾添加一个元素
136 *
137 * @param pList 目标线性表
138 * @param pe 指向待添加元素的指针
139 *
140 * @return 返回添加成功后当前线性表长度
141 */
142 int AppendElem( mList *pList, ElemType *pt )
143 {
144     ListNode *pm = pList->head, *pn = NULL;
145 
146     while( pm->next != NULL ) { pm = pm->next; };
147     pn = (ListNode *)malloc(sizeof(ListNode));
148     pn->pt.x = pt->x;
149     pn->pt.y = pt->y;
150     pn->next = NULL;
151     pm->next = pn;
152 
153     return ++pList->length;
154 }
155 
156 /**
157 * @brief 向线性表中插入一个元素
158 *
159 * @param pList 指向待插入元素的线性表
160 * @param nPos 插入的位置
161 * @param pt 指向待插入的元素的指针
162 *
163 * @return 若插入成功则返回插入后线性表当前长度, 否则返回 -1
164 *
165 * @note 插入位置 nPos 从 0 计起
166 */
167 int InsertElem( mList *pList, int nPos, ElemType *pt )
168 {
169     ListNode *pm = pList->head, *pn = NULL;
170 
171     if( nPos < 0 || nPos > pList->length - 1 )         ///插入位置是否在线性表内
172         return -1;
173 
174     int n = 0;
175     for( n = 0; n < nPos; ++n, (pm = pm->next) );
176     pn = (ListNode *)malloc(sizeof(ListNode));
177     pn->pt.x = pt->x;
178     pn->pt.y = pt->y;
179 
180     pn->next = pm->next;
181     pm->next = pn;
182 
183     return ++pList->length;
184 }
185 
186 /**
187 * @brief 从线性表中删除一个元素
188 *
189 * @param pList 指向待删除元素的线性表指针
190 * @param nPos 待删除元素的位置
191 *
192 * @return 若删除成功则返回删除后线性表当前长度, 否则返回 -1
193 *
194 * @note 删除位置 nPos 从 0 计起
195 */
196 int DeleteElem( mList *pList, int nPos )
197 {
198     ListNode *pm = pList->head, *pn = NULL;
199 
200     if( nPos < 0 || nPos > pList->length - 1 )         ///删除位置是否在线性表内
201         return -1;
202 
203     int i = 0;
204     for( i = 0; i < nPos; ++i, (pm = pm->next) );
205     pn = pm->next;
206     pm->next = pn->next;
207     free(pn);
208 
209     return --pList->length;
210 }
211 
212 /**
213 * @brief 获取线性表中某位置上的元素
214 *
215 * @param pList 指向待获取元素的线性表指针
216 * @param nPos 元素在线性表中的位置
217 * @param pt 指向存放获取到的元素的指针
218 *
219 * @return 若获取成功, 返回 TRUE, 否则返回 FALSE
220 *
221 * @note 元素位置从 0 计起
222 */
223 int GetElem( mList *pList, int nPos, ElemType *pt )
224 {
225     int n = nPos;
226     if( n < 0 || n > pList->length - 1 )
227         return FALSE;
228 
229     ListNode *pm = pList->head;
230     for( n = 0; n <= nPos; ++n, (pm = pm->next) );
231     pt->x = pm->pt.x;
232     pt->y = pm->pt.y;
233 
234     return TRUE;
235 }
236 
237 /**
238 * @brief 从某位置起查找某元素在线性表中第一次出现的位置
239 *
240 * @param pList 指向待查找元素的线性表的指针
241 * @param nPos 查找起始位置
242 * @param pt 指向待查找的元素的指针
243 *
244 * @return 若找到, 则返回元素所在的位置, 否则返回 -1
245 *
246 * @note 起始位置由 0 计起
247 */
248 int FindElem( mList *pList, int nPos, ElemType *pt )
249 {
250     int n = nPos;
251     if( n < 0 || n > pList->length - 1 )
252         return -1;
253 
254     ListNode *pm = pList->head;
255     for( n = 0; n <= nPos; ++n, (pm = pm->next) );
256     for( ; pm != NULL; ++n )
257     {
258         if( (pm->pt.x == pt->x) && (pm->pt.y == pt->y) )
259             return n-1;
260 
261         pm = pm->next;
262     }
263 
264     return -1;
265 }
266 
267 /**
268 * @brief 获取某 pt 元素的前驱节点到 prior_pt
269 *
270 * @param 指向待获取前驱节点的线性表指针
271 * @param pt 指向目标节点的指针
272 * @param prior_pt 存放目标节点 pt 的前驱节点
273 *
274 * @return 若成功获取前驱节点, 返回该前驱节点在线性表中的位置, 否则返回 -1
275 *
276 * @note 元素位置从 0 计起
277 */
278 int GetPriorElem( mList *pList, ElemType *pt, ElemType *prior_pt )
279 {
280     ListNode *pm = pList->head;
281     int ncnt = 0;
282     while( pm->next != NULL )
283     {
284         if( pm->next->pt.x == pt->x && pm->next->pt.y == pt->y )
285         {
286             if( ncnt != 0 )         ///不为首节点
287             {
288                 prior_pt->x = pm->pt.x;
289                 prior_pt->y = pm->pt.y;
290                 return ncnt - 1;
291             }
292             else return -1;      ///不存在前驱节点
293         }
294         pm = pm->next;
295         ++ncnt;
296     }
297 
298     return -1;
299 }
300 
301 /**
302 * @brief 获取某 pt 元素的后继节点到 next_pt
303 *
304 * @param 指向待获取前后继点的线性表指针
305 * @param pt 指向目标节点的指针
306 * @param prior_pt 存放目标节点 pt 的后继节点
307 *
308 * @return 若成功获取后继节点, 返回该后继节点在线性表中的位置, 否则返回 -1
309 *
310 * @note 元素位置从 0 计起
311 */
312 int GetNextElem( mList *pList, ElemType *pt, ElemType *next_pt )
313 {
314     ListNode *pm = pList->head;
315     int ncnt = 0;
316     while( (pm = pm->next) != NULL )
317     {
       if( ncnt == pList->length )  //bug修复, 不存在后继节点
          return -1;
318 if( pm->pt.x == pt->x && pm->pt.y == pt->y ) 319 { 320 if( pm->next != NULL ) 321 { 322 next_pt->x = pm->next->pt.x; 323 next_pt->y = pm->next->pt.y; 324 325 return ncnt + 1; 326 } 327 } 328 ++ncnt; 329 } 330 331 return -1; 332 } 333 334 /** 335 * @brief 对线性表中每个元素执行 func 函数 336 * 337 * @param pList 指向待处理的线性表的指针 338 * @param func 传入的函数指针 339 * 340 * @return void 341 */ 342 void ForEachList( mList *pList, void (*func)(ElemType *pt) ) 343 { 344 ListNode *pm = pList->head; 345 while( (pm = pm->next) != NULL ) 346 func( &pm->pt ); 347 } 348 349 /** 350 * @brief 将 pSrcList 性表复制到 pDestList 线性表后 351 * 352 * @param pDestList 指向目标线性表指针 353 * @param pSrcList 指向源线性表指针 354 * 355 * @return 返回复制后目标线性表长度 356 */ 357 int ListCpy( mList *pDestList, mList *pSrcList ) 358 { 359 ListNode *pm = pDestList->head; 360 ListNode *pn = pSrcList->head; 361 ListNode *ptmp = NULL; 362 363 while( pm->next != NULL ) pm = pm->next; 364 while( (pn = pn->next) != NULL ) 365 { 366 ptmp = (ListNode *)malloc(sizeof(ListNode)); 367 ptmp->pt.x = pn->pt.x; 368 ptmp->pt.y = pn->pt.y; 369 pm->next = ptmp; 370 pm = pm->next; 371 } 372 pm->next = NULL; 373 pDestList->length += pSrcList->length; 374 375 return pDestList->length; 376 } 377 378 /** 379 * @brief 将 pSrcList 性表连接到 pDestList 线性表后 380 * 381 * @param pDestList 指向目标线性表指针 382 * @param pSrcList 指向源线性表指针 383 * 384 * @return 返回连接后目标线性表长度 385 * 386 * @note 连接后 pSrcList 线性表将被销毁 387 */ 388 int ListCat( mList *pDestList, mList *pSrcList ) 389 { 390 ListNode *pm = pDestList->head; 391 while( pm->next != NULL ) pm = pm->next; 392 pm->next = pSrcList->head->next; 393 pDestList->length += pSrcList->length; 394 free( pSrcList ); 395 396 return pDestList->length; 397 } 398 399 //测试 mList 400 401 void display( ElemType *pt ) 402 { 403 printf("(%d,%d) ", pt->x, pt->y); 404 } 405 406 int main() 407 { 408 mList *plstA = CreateList(), *plstB = CreateList(); //创建 plst 与 plst2 两根空线性表 409 ElemType pt, pt2; //两个 ElemType 型元素 410 411 int i = 0; 412 for( i = 0; i < 10; ++i ) 413 { 414 pt.x = i; 415 pt.y = i; 416 AppendElem( plstA, &pt ); //向 plst 循环添加 (0,0) 至 (10,10) 417 } 418 419 for( i = 55; i < 60; ++i ) 420 { 421 pt.x = i; 422 pt.y = i; 423 AppendElem( plstB, &pt ); //向 plst 循环添加 (55,55) 至 (60,60) 424 } 425 426 ///测试 ForEachList 427 printf("plstA 初始数据: "); 428 ForEachList( plstA, display ); //对线性表中每个元素执行 display 函数 429 430 printf("\nplstB 初始数据: "); 431 ForEachList( plstB, display ); 432 433 ///测试 InsertElem 434 printf("\n\n向 plstA 位置3处插入元素(100,99)后:\n"); 435 pt.x = 100; pt.y = 99; 436 InsertElem( plstA, 3, &pt ); //向 plstA 位置 3 处插入 pt 437 ForEachList( plstA, display ); 438 439 ///测试 DeleteElem 440 printf("\n\n删除 plstB 位置0处的元素后:\n"); 441 DeleteElem( plstB, 0 ); //删除 plstA 位置 0 处的元素 442 ForEachList( plstB, display ); 443 444 ///测试 IsEmpty、GetLength 445 printf("\n\n线性表 plstA 是否为空: %d\n", IsEmpty(plstA) ); 446 printf("线性表 plstB 的长度: %d\n", GetLength(plstB) ); 447 448 ///测试 GetElem 449 GetElem( plstA, 5, &pt ); 450 printf("获取 plstA 位置 5 的元素: (%d, %d)\n", pt.x, pt.y ); 451 452 ///测试 FindElem 453 pt.x = 6; pt.y = 6; 454 printf("获取元素(6,6)在线性表plstA中的位置: %d\n", FindElem(plstA, 0, &pt)); 455 456 ///测试 GetPriorElem 457 GetPriorElem( plstA, &pt, &pt2 ); 458 printf("获取pt=(6,6)在plstA中的前驱节点: (%d,%d)\n", pt2.x, pt2.y); 459 460 ///测试 GetNextElem 461 GetNextElem( plstA, &pt, &pt2 ); 462 printf("获取pt=(6,6)在plstA中的后继节点: (%d,%d)\n", pt2.x, pt2.y); 463 464 ///测试 ListCpy 465 printf("\n将 plstB 复制到 plstA 后:\n"); 466 ListCpy( plstA, plstB ); 467 ForEachList( plstA, display ); 468 printf("\nplstA长度=%d\n", GetLength(plstA)); 469 470 ///测试 ListCat 471 printf("\n将 plstB 连接到 plstA 后:\n"); 472 ListCat( plstA, plstB ); 473 ForEachList( plstA, display ); 474 printf("\nplstA长度=%d\n", GetLength(plstA)); 475 476 ///测试 ClearList 477 printf("\n置空 plstA 线性表:\n"); 478 ClearList(plstA); 479 printf("plstA 长度=%d\n", GetLength(plstA)); 480 481 ///测试 DestroyList 482 printf("销毁 plstA.."); 483 DestroyList(plstA); 484 485 return 0; 486 }

若代码存在 bug 或程序缺陷, 请留言反馈, 谢谢。