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