C语言 线性表 双向链式结构 实现
2013-10-28 17:55 wid 阅读(1096) 评论(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 或程序缺陷, 请留言反馈, 谢谢。