一個雙向鏈式結構實現的線性表 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 或程序缺陷, 請留言反饋, 謝謝。 測試