一個可以自動擴容的順序表 ArrList (GCC編譯)。函數
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 #define TRUE 1 6 #define FALSE 0 7 8 typedef struct 9 { 10 int x; 11 int y; 12 }Point2D; // Point2D 結構 13 14 typedef struct 15 { 16 Point2D *pt; //線性表的數據項 17 int length; //線性表當前長度 18 int size; //線性表總容量 19 }ArrList; // ArrList 結構 20 21 22 //聲明線性表所具備的方法 23 ArrList *CreateArrList( int nLength ); //建立長爲 nArrLength 的線性表 24 void DestroyArrList( ArrList *pArrList ); //銷燬線性表 pArrList 25 void ClearArrList( ArrList *pArrList ); //置空線性表 pArrList 26 int IsEmptyArrList( ArrList *pArrList ); //檢測線性表是否爲空 27 int GetArrListLength( ArrList *pArrList ); //獲取線性表長度 28 int GetArrListSize( ArrList *pArrList ); //獲取線性表總容量 29 int GetArrListElement( ArrList *pArrList, int n, Point2D *pt ); //獲取線性表中第n個元素 30 int FindElement( ArrList *pArrList, int nPos, Point2D *pt ); //從 nPos 起查找 pt 第一次出現的位置 31 int GetPriorElement( ArrList *pArrList, Point2D *pt, Point2D *prior_pt ); //獲取 pt 的前驅節點到 prior_pt 32 int GetNextElement( ArrList *pArrList, Point2D *pt, Point2D *next_pt ); //獲取 pt 的後繼節點到 next_pt 33 int AppendToArrList( ArrList *pArrList, Point2D *pt ); //將 pt 添加到線性表末尾處 34 int InsertToArrList( ArrList *pArrList, int nPos, Point2D *pt ); //將 pt 插入到 nPos 處 35 int DeleteFromArrList( ArrList *pArrList, int nPos ); //刪除線性表上位置爲 nPos 的元素 36 void ForEachArrList( ArrList *pArrList, void (*func)(Point2D *pt) ); //對線性表中每一個元素執行 func 函數 37 int ArrListCpy( ArrList *pArrListDest, ArrList *pArrListSrc ); //將線性表 pArrListSrc 複製到 pArrListDest 38 int ArrListCat( ArrList *pArrListDest, ArrList *pArrListSrc ); //將線性表 pArrListSrc 鏈接到 pArrListDest 的末尾 39 40 41 //線性表方法實現 42 /** 43 * @brief 建立長度爲 nLength 的線性表 ArrList 44 * 45 * @param nLength 所要構建的線性表長度 46 * 47 * @return 指向所建立的線性表的指針 48 */ 49 ArrList *CreateArrList( int nLength ) 50 { 51 ArrList *pl = (ArrList *)malloc( sizeof(ArrList) ); 52 53 pl->pt = (Point2D *)calloc( nLength, sizeof(Point2D) ); 54 pl->length = 0; 55 pl->size = nLength; 56 57 return pl; 58 } 59 60 /** 61 * @brief 銷燬一條線性表 62 * 63 * @param pArrList 指向待銷燬線性表的指針 64 * 65 * @return void 66 */ 67 void DestroyArrList( ArrList *pArrList ) 68 { 69 free( pArrList->pt ); ///先釋放線性表pt 70 free( pArrList ); ///銷燬線性表pArrList 71 } 72 73 /** 74 * @brief 置空一條線性表 75 * 76 * @param pArrList 指向待置空線性表的指針 77 * 78 * @return void 79 */ 80 void ClearArrList( ArrList *pArrList ) 81 { 82 pArrList->length = 0; 83 } 84 85 /** 86 * @brief 檢測線性表是否爲空 87 * 88 * @param pArrList 指向待檢測線性表的指針 89 * 90 * @return 爲空則返回 TRUE, 不然返回 FALSE 91 */ 92 int IsEmptyArrList( ArrList *pArrList ) 93 { 94 return pArrList->length == 0 ? TRUE : FALSE; 95 } 96 97 /** 98 * @brief 獲取線性表長度 99 * 100 * @param pArrList 指向待獲取長度的線性表的指針 101 * 102 * @return 返回獲取到的線性表長度 103 */ 104 int GetArrListLength( ArrList *pArrList ) 105 { 106 return pArrList->length; 107 } 108 109 /** 110 * @brief 獲取線性表總容量 111 * 112 * @param pArrList 指向待獲取容量的線性表的指針 113 * 114 * @return 返回獲取到的線性表的總容量 115 */ 116 int GetArrListSize( ArrList *pArrList ) 117 { 118 return pArrList->size; 119 } 120 121 /** 122 * @brief 獲取線性表中第 n 個元素 123 * 124 * @param pArrList 指向待獲取其中的元素的線性表的指針 125 * @param n 要獲取的第 n 個元素 126 * @param pt 用於存放獲取到的元素的值的 Point2D 類型指針 127 * 128 * @return 獲取成功返回 TRUE, 不然返回 FALSE 129 * 130 * @note 元素n, n 從 0 起 131 */ 132 int GetArrListElement( ArrList *pArrList, int n, Point2D *pt ) 133 { 134 if( n < 0 || n > pArrList->length-1 ) 135 return FALSE; 136 137 pt->x = pArrList->pt[n].x; 138 pt->y = pArrList->pt[n].y; 139 140 return TRUE; 141 } 142 143 /** 144 * @brief 從 nPos 處查找元素 pt 第一次出現的位置 145 * 146 * @param pArrList 指向待查找其中的元素的線性表的指針 147 * @param nPos 查找起始位置 148 * @param pt 指向待查找元素的指針 149 * 150 * @return 若找到, 返回元素 pt 在線性表中的位置(下標), 不然返回 -1 151 * 152 * @note 位置從 0 計起 153 */ 154 int FindElement( ArrList *pArrList, int nPos, Point2D *pt ) 155 { 156 int n = nPos; 157 for( n; n < pArrList->length; ++n ) 158 { 159 if( (pArrList->pt[n].x == pt->x) && (pArrList->pt[n].y == pt->y) ) 160 return n; 161 } 162 163 return -1; 164 } 165 166 /** 167 * @brief 獲取線性表中 pt 元素的前驅節點到 prior_pt 168 * 169 * @param pArrList 指向待獲取其中的元素的線性表的指針 170 * @param pt 指向目標節點的指針 171 * @param prior_pt 存放查找到的目標節點的前驅節點 172 * 173 * @return 若獲取到前驅節點, 返回目標節點的前驅節點在線性表中的位置(下標), 不然返回 -1 174 * 175 * @note 位置從 0 計起 176 */ 177 int GetPriorElement( ArrList *pArrList, Point2D *pt, Point2D *prior_pt ) 178 { 179 int n = 0; 180 for( n = 0; n < pArrList->length; ++n ) 181 { 182 if( (pArrList->pt[n].x == pt->x) && (pArrList->pt[n].y == pt->y) ) 183 { 184 if( n <= 0 ) ///目標節點是頭節點, 無前驅節點 185 return -1; 186 else ///存在並找到前驅節點 187 { 188 prior_pt->x = pArrList->pt[n-1].x; 189 prior_pt->y = pArrList->pt[n-1].y; 190 191 return n-1; 192 } 193 } 194 } 195 196 return -1; 197 } 198 199 /** 200 * @brief 獲取線性表中 pt 元素的後繼節點到 next_pt 201 * 202 * @param pArrList 指向待獲取其中的元素的線性表的指針 203 * @param pt 指向目標節點的指針 204 * @param next_pt 存放查找到的目標節點的後繼節點 205 * 206 * @return 若獲取到後繼節點, 返回目標節點的後繼節點在線性表中的位置(下標), 不然返回 -1 207 * 208 * @note 位置從 0 計起 209 */ 210 int GetNextElement( ArrList *pArrList, Point2D *pt, Point2D *next_pt ) 211 { 212 int n = 0; 213 for( n = 0; n < pArrList->length; ++n ) 214 { 215 if( (pArrList->pt[n].x == pt->x) && (pArrList->pt[n].y == pt->y) ) 216 { 217 if( n >= pArrList->length-1 ) ///目標節點是尾節點, 無後繼節點 218 return -1; 219 else ///存在並找到後繼節點 220 { 221 next_pt->x = pArrList->pt[n+1].x; 222 next_pt->y = pArrList->pt[n+1].y; 223 224 return n+1; 225 } 226 } 227 } 228 229 return -1; 230 } 231 232 /** 233 * @brief 添加一個元素至線性表末尾 234 * 235 * @param pArrList 指向待添加元素的線性表的指針 236 * @param pt 指向待添加的元素的指針 237 * 238 * @return 成功添加則返回當前線性表長度, 不然返回 -1 239 */ 240 int AppendToArrList( ArrList *pArrList, Point2D *pt ) 241 { 242 if( pArrList->size - pArrList->length < 1 ) ///檢測是否須要擴容 243 { 244 Point2D *p = (Point2D *)calloc(pArrList->length * 2, sizeof(Point2D)); 245 memcpy( p, pArrList->pt, pArrList->length*sizeof(Point2D) ); 246 pArrList->size = pArrList->length * 2; 247 free( pArrList->pt ); 248 pArrList->pt = p; 249 } 250 251 pArrList->pt[pArrList->length].x = pt->x; 252 pArrList->pt[pArrList->length].y = pt->y; 253 254 return ++pArrList->length; 255 } 256 257 /** 258 * @brief 插入一個元素 pt 到線性表 nPos 處 259 * 260 * @param pArrList 指向待插入元素的線性表指針 261 * @param nPos 插入的位置(下標) 262 * @param pt 指向待插入的元素的指針 263 * 264 * @return 插入成功則返回當前線性表長度, 不然返回 -1 265 * 266 * @note 插入位置 nPos 從 0 計起 267 */ 268 int InsertToArrList( ArrList *pArrList, int nPos, Point2D *pt ) 269 { 270 if( (nPos < 0) || (nPos > pArrList->length-1) ) 271 return -1; 272 273 if( pArrList->size - pArrList->length < 1 ) ///檢測是否須要擴容 274 { 275 Point2D *p = (Point2D *)calloc(pArrList->length*2, sizeof(Point2D)); 276 memcpy( p, pArrList->pt, pArrList->length * sizeof(Point2D) ); 277 pArrList->size = pArrList->length * 2; 278 free( pArrList->pt ); 279 pArrList->pt = p; 280 } 281 282 int nMax = pArrList->length; ///獲取線性表插入1元素後的長度 283 for( nMax; nMax > nPos; --nMax ) 284 { 285 pArrList->pt[nMax].x = pArrList->pt[nMax-1].x; 286 pArrList->pt[nMax].y = pArrList->pt[nMax-1].y; 287 } 288 pArrList->pt[nPos].x = pt->x; 289 pArrList->pt[nPos].y = pt->y; 290 291 return ++pArrList->length; 292 } 293 294 /** 295 * @brief 從線性表上刪除一個元素 296 * 297 * @param pArrList 指向待處理線性表的指針 298 * @param nPos 須要刪除的元素位置(下標) 299 * 300 * @return 成功刪除返回刪除後線性表長度, 不然返回 -1 301 * 302 * @note 刪除位置 nPos 從 0 計起 303 */ 304 int DeleteFromArrList( ArrList *pArrList, int nPos ) 305 { 306 if( (nPos < 0) || (nPos > pArrList->length - 1) ) 307 return -1; 308 309 if( nPos == pArrList->length - 1 ) 310 return --pArrList->length; 311 312 for( nPos; nPos < pArrList->length; ++nPos ) 313 { 314 pArrList->pt[nPos].x = pArrList->pt[nPos+1].x; 315 pArrList->pt[nPos].y = pArrList->pt[nPos+1].y; 316 } 317 318 return --pArrList->length; 319 } 320 321 /** 322 * @brief 對線性表中的元素依次執行傳入的函數 323 * 324 * @param pArrList 指向待處理的線性表的指針 325 * @param func 傳入的函數指針 326 * 327 * @return void 328 * 329 * @note 傳入的函數的參數爲線性表元素類型的指針 330 */ 331 void ForEachArrList( ArrList *pArrList, void (*func)(Point2D *pt) ) 332 { 333 int i = 0; 334 for( i = 0; i < pArrList->length; ++i ) 335 { 336 func( &pArrList->pt[i] ); 337 } 338 } 339 340 /** 341 * @brief 將線性表 pArrListSrc 複製到目標線性表 pArrListDest 342 * 343 * @param pArrListDest 目標線性表 344 * @param pArrListSrc 源線性表 345 * 346 * @return 成功則返回複製後的目標線性表的長度, 不然返回 -1 347 */ 348 int ArrListCpy( ArrList *pArrListDest, ArrList *pArrListSrc ) 349 { 350 if( pArrListDest->size - pArrListSrc->length < 0 ) ///目標線性表是否須要擴容 351 { 352 free(pArrListDest->pt); 353 Point2D *p = (Point2D *)calloc(pArrListSrc->length, sizeof(Point2D)); 354 pArrListDest->pt = p; 355 pArrListDest->size = pArrListSrc->length; 356 } 357 358 memcpy( pArrListDest->pt, pArrListSrc->pt, pArrListSrc->length * sizeof(Point2D) ); 359 pArrListDest->length = pArrListSrc->length; 360 361 return pArrListDest->length; 362 } 363 364 /** 365 * @brief 將線性表 pArrListSrc 鏈接到目標線性表 pArrListDest 366 * 367 * @param pArrListDest 目標線性表 368 * @param pArrListSrc 源線性表 369 * 370 * @return 成功則返回鏈接後的目標線性表的長度, 不然返回 -1 371 */ 372 int ArrListCat( ArrList *pArrListDest, ArrList *pArrListSrc ) 373 { 374 if( pArrListDest->size - pArrListDest->length < pArrListSrc->length ) ///目標線性表是否須要擴容 375 { 376 Point2D *p = (Point2D *)calloc(pArrListDest->length + pArrListSrc->length, sizeof(Point2D)); 377 memcpy( p, pArrListDest->pt, pArrListDest->length * sizeof(Point2D) ); 378 free(pArrListDest->pt); 379 pArrListDest->pt = p; 380 pArrListDest->size = pArrListDest->length + pArrListSrc->length; 381 } 382 383 int pos = 0; 384 for(pos; pos < pArrListSrc->length; ++pos ) 385 { 386 pArrListDest->pt[pArrListDest->length + pos].x = pArrListSrc->pt[pos].x; 387 pArrListDest->pt[pArrListDest->length + pos].y = pArrListSrc->pt[pos].y; 388 } 389 390 pArrListDest->length += pArrListSrc->length; 391 392 return pArrListDest->length; 393 } 394 395 //測試線性表 ArrList 396 397 //回調函數 398 void display( Point2D *pt ) 399 { 400 printf( "(%d,%d) ", pt->x, pt->y ); 401 } 402 403 int main() 404 { 405 Point2D pt1, pt2; 406 ArrList *plstA = CreateArrList( 10 ); //建立一個長度爲 10 的線性表 plstA 407 408 /// 409 printf("測試添加元素..\n"); 410 int i = 0; 411 for( i; i < 10; ++i ) 412 { 413 pt1.x = i; pt1.y = i; 414 AppendToArrList( plstA, &pt1 ); //測試添加 415 } 416 ForEachArrList( plstA, display ); //對每一個元素執行 display 417 printf( "\nplstA len = %d, size = %d\n", GetArrListLength(plstA), GetArrListSize(plstA) ); 418 419 /// 420 printf("\n測試被動擴容添加..\n"); 421 for( i = 10; i < 35; ++i ) 422 { 423 pt1.x = i; pt1.y = i; 424 AppendToArrList( plstA, &pt1 ); //測試被動擴容 425 } 426 ForEachArrList( plstA, display ); 427 printf( "\nplstA len = %d, size = %d\n", GetArrListLength(plstA), GetArrListSize(plstA) ); 428 429 /// 430 printf("\n測試插入到頭部、尾部..\n"); 431 pt1.x = 100; pt1.y = 100; 432 InsertToArrList( plstA, 0, &pt1 ); //測試插入到首部 433 InsertToArrList( plstA, GetArrListLength(plstA)-1, &pt1 ); //測試插入到尾部 434 ForEachArrList( plstA, display ); 435 printf( "\nplstA len = %d, size = %d\n", GetArrListLength(plstA), GetArrListSize(plstA) ); 436 437 /// 438 printf("\n測試獲取節點元素..\n"); 439 GetArrListElement( plstA, 5, &pt2 ); //獲取節點位置爲5的元素 440 printf("節點座標爲5的元素pt2: (%d,%d)\n", pt2.x, pt2.y); 441 442 /// 443 printf("\n測試獲取某元素的前驅節點..\n"); 444 Point2D pri_pt, next_pt; 445 GetPriorElement( plstA, &pt2, &pri_pt ); //獲取 pt2 的前驅節點 446 printf("pt2的前驅節點: (%d, %d)\n", pri_pt.x, pri_pt.y); 447 GetNextElement( plstA, &pt2, &next_pt ); //獲取 pt2 的後繼節點 448 printf("pt2的後繼節點: (%d, %d)\n", next_pt.x, next_pt.y); 449 450 /// 451 printf("\n測試查找元素..\n"); 452 printf("元素 next_pt 在線性表中第一次出現的位置: %d\n", FindElement(plstA, 0, &next_pt)); //從 0 起查找元素 next_pt 453 454 /// 455 printf("\n測試刪除某元素..\n"); 456 printf("刪除位置爲0的元素: "); 457 DeleteFromArrList( plstA, 0 ); //刪除節點位置爲0的元素 458 ForEachArrList( plstA, display ); 459 printf( "\nplstA len = %d, size = %d\n", GetArrListLength(plstA), GetArrListSize(plstA) ); 460 461 /// 462 printf("\n測試複製線性表..\n"); 463 printf("建立線性表 plstB : "); 464 ArrList *plstB = CreateArrList( 50 ); 465 for( i = 50; i < 60; ++i ) 466 { 467 pt2.x = i; pt2.y = i; 468 AppendToArrList( plstB, &pt2 ); 469 } 470 ForEachArrList( plstB, display ); 471 printf( "\nplstB len = %d, size = %d\n", GetArrListLength(plstB), GetArrListSize(plstB) ); 472 printf("將 plstB 複製到 plstA: \n"); 473 ArrListCpy( plstA, plstB ); //將線性表 plstB 複製到 plstA 474 ForEachArrList( plstA, display ); 475 printf( "plstA len = %d, size = %d\n", GetArrListLength(plstA), GetArrListSize(plstA) ); 476 477 /// 478 printf("\n測試鏈接線性表..\n"); 479 printf("將 plstB 鏈接到 plstA: "); 480 ArrListCat( plstA, plstB ); //將線性表 plstB 鏈接到 plstA 481 ForEachArrList( plstA, display ); 482 printf( "\nplstA len = %d, size = %d\n", GetArrListLength(plstA), GetArrListSize(plstA) ); 483 484 /// 485 printf("\n測試清空線性表..\n"); 486 ClearArrList( plstA ); //清空線性表 plstA 487 ForEachArrList( plstA, display ); 488 printf( "plstA len = %d, size = %d\n", GetArrListLength(plstA), GetArrListSize(plstA) ); 489 printf( "IsEmpty = %d\n", IsEmptyArrList(plstA) ); 490 491 /// 492 printf("\n銷燬線性表..\n"); 493 DestroyArrList( plstA ); //銷燬線性表, 釋放資源 494 DestroyArrList( plstB ); 495 496 return 0; 497 }
若存在 bug 或程序缺陷, 請留言反饋, 謝謝。測試