http://blog.csdn.net/fisherwan/article/details/19754585
昨天寫了單向鏈表的代碼,今天上午把單向循環鏈表的程序給敲完了。鏈表的相關操作一樣的,包含鏈表的創建、判斷鏈表是否為空、計算鏈表長度、向鏈表中插入節點、從鏈表中刪除節點、刪除整個鏈表釋放內存。如果單向鏈表理解了,那單向循環鏈表也就不難了。
單向循環鏈表如下圖所示:
看圖可以知道,單向循環鏈表和單向鏈表差不多,只不過是最后的尾節點指向的不是空,而是指向頭節點。理解這一點很重要,因為這是我們寫程序的關鍵。下面我們上代碼:
SqCcLinkList.h 頭文件——定義了節點結構體,以及相關操作的函數聲明。
[cpp]?view plain
?copy #ifndef?ONE_WAY_CIRCULAR_LINK_LIST_H?? #define?ONE_WAY_CIRCULAR_LINK_LIST_H?? ?? typedef?struct?Node?? {?? ????int?data;?? ????struct?Node?*pNext;?? }NODE,?*pNODE;?? ?? ?? pNODE?CreateSgCcLinkList(void);?? ?? ?? void?TraverseSgCcLinkList(pNODE?pHead);?? ?? ?? int?IsEmptySgCcLinkList(pNODE?pHead);?? ?? ?? int?GetLengthSgCcLinkList(pNODE?pHead);?? ?? ?? int?InsertEleSgCcLinkList(pNODE?pHead,?int?pos,?int?data);?? ?? ?? int?DeleteEleSgCcLinkList(pNODE?pHead,?int?pos);?? ?? ?? void?FreeMemory(pNODE?*ppHead);?? ?? #endif??
SqCcLinkList.cpp
鏈表源文件——這里包含了各種相關操作的函數的定義。
(1)這部分是創建鏈表,和單向鏈表一樣,一開始也是創建了一個頭節點,初始化時,頭結點的指針指向自己(這是和單向鏈表不一樣的地方)。在寫程序時,主要體現在下面的一行代碼:
[cpp]?view plain
?copy p_new->pNext?=?pHead;??????
它的意思就是沒創建一個節點,讓這個節點指向頭節點,然后就形成了一個環,也就成了循環鏈表。
[cpp]?view plain
?copy #include?<stdio.h>?? #include?<stdlib.h>?? #include?"SgCcLinkLIst.h"?? ?? ?? pNODE?CreateSgCcLinkList(void)?? {?? ????int?i,?length?=?0,?data?=?0;?? ????pNODE?pTail?=?NULL,?p_new?=?NULL;?? ????pNODE?pHead?=?(pNODE)malloc(sizeof(NODE));?? ?? ????if?(NULL?==?pHead)?? ????{?? ????????printf("內存分配失敗!\n");?? ????????exit(EXIT_FAILURE);?? ????}?? ?????? ????pHead->data?=?0;?? ????pHead->pNext?=?pHead;?? ????pTail?=?pHead;?? ?? ????printf("請輸入要創建鏈表的長度:");?? ????scanf("%d",?&length);?? ?? ????for?(i=1;?i<length+1;?i++)?? ????{?? ????????p_new?=?(pNODE)malloc(sizeof(NODE));?? ?? ????????if?(NULL?==?p_new)?? ????????{?? ????????????printf("內存分配失敗!\n");?? ????????????exit(EXIT_FAILURE);?? ????????}?? ?? ????????printf("請輸入第%d個節點的元素值:",?i);?? ????????scanf("%d",?&data);?? ?? ????????p_new->data?=?data;?? ????????p_new->pNext?=?pHead;?????? ????????pTail->pNext?=?p_new;?? ????????pTail?=?p_new;?? ????}?? ?? ????return?pHead;?? }??
(2)這部分是獲得鏈表的相關信息,和單向鏈表一樣,頭節點不參與運算;但是和單向鏈表不同的地方就是判斷的時候是和頭結點進行比較,如何相等的話呢,說明到了鏈表的結尾。
[cpp]?view plain
?copy ?? void?TraverseSgCcLinkList(pNODE?pHead)?? {?? ????pNODE?pt?=?pHead->pNext;?? ?? ????printf("鏈表打印如:");?? ????while?(pt?!=?pHead)?? ????{?? ????????printf("%d?",?pt->data);?? ????????pt?=?pt->pNext;?? ????}?? ????putchar('\n');?? }?? ?? ?? int?IsEmptySgCcLinkList(pNODE?pHead)?? {?? ????if?(pHead->pNext?==?pHead)?? ????????return?1;?? ????else?? ????????return?0;?? }?? ?? ?? int?GetLengthSgCcLinkList(pNODE?pHead)?? {?? ????int?length?=?0;?? ????pNODE?pt?=?pHead->pNext;?? ?? ????while?(pt?!=?pHead)?? ????{?? ????????length++;?? ????????pt?=?pt->pNext;?? ????}?? ????return?length;?? }??
(3)這部分是鏈表的插入和刪除操作,和單向鏈表一樣。
[cpp]?view plain
?copy ?? int?InsertEleSgCcLinkList(pNODE?pHead,?int?pos,?int?data)?? {?? ????pNODE?p_new?=?NULL;?? ?? ????if?(pos?>?0?&&?pos?<?GetLengthSgCcLinkList(pHead)?+?2)?? ????{?? ????????p_new?=?(pNODE)malloc(sizeof(NODE));?? ?? ????????if?(NULL?==?<span?style="font-family:?Arial,?Helvetica,?sans-serif;">p_new?</span><span?style="font-family:?Arial,?Helvetica,?sans-serif;">)</span>?? ????????{?? ????????????printf("內存分配失敗!\n");?? ????????????exit(EXIT_FAILURE);?? ????????}?? ?? ????????while?(1)?? ????????{?? ????????????pos--;?? ????????????if?(0?==?pos)?? ????????????????break;?? ????????????pHead?=?pHead->pNext;?? ????????}?? ?????????? ????????p_new->data?=?data;?? ????????p_new->pNext?=?pHead->pNext;?? ????????pHead->pNext?=?p_new;?? ?? ????????return?1;?? ????}?? ????else?? ????????return?0;?? }??
[cpp]?view plain
?copy <span?style="font-family:?Arial,?Helvetica,?sans-serif;">??
[cpp]?view plain
?copy int?DeleteEleSgCcLinkList(pNODE?pHead,?int?pos)?? {?? ????pNODE?pt?=?NULL;?? ?? ????if?(pos?>?0?&&?pos?<?GetLengthSgCcLinkList(pHead)?+?1)?? ????{?? ????????while?(1)?? ????????{?? ????????????pos--;?? ????????????if?(0?==?pos)?? ????????????????break;?? ????????????pHead?=?pHead->pNext;?? ????????}?? ?? ????????pt?=?pHead->pNext->pNext;?? ????????free(pHead->pNext);?? ????????pHead->pNext?=?pt;?? ?? ????????return?1;?? ????}?? ????else?? ????????return?0;?? }??
(4)這部分是釋放內存,和單向鏈表有些不一樣,因為單向循環鏈表是個環,最后只剩下頭節點的時候要單獨處理,這個受我判斷條件的限制。當然可能有更好的方法,我們可以共同討論。這里我分了兩種情況來釋放內存。
[cpp]?view plain
?copy ?? void?FreeMemory(pNODE?*ppHead)?? {?? ????pNODE?pt?=?NULL;?? ?? ????while?(*ppHead?!=?NULL)?? ????{?? ????????if?(*ppHead?==?(*ppHead)->pNext)??? ????????{?? ????????????free(*ppHead);?? ????????????*ppHead?=?NULL;?? ????????}?? ????????else?????????????????????? ????????{?? ????????????pt?=?(*ppHead)->pNext->pNext;?? ????????????free((*ppHead)->pNext);?? ????????????(*ppHead)->pNext?=?pt;?? ????????}?? ????}?? }??
main.cpp
測試程序源文件——這個程序通過一些簡單的交互用來測試各個函數是否實現了各自的功能。
[cpp]?view plain
?copy #include?<stdio.h>?? #include?<stdlib.h>?? #include?"SgCcLinkList.h"?? ?? int?main(void)?? {?? ????int?flag?=?0,?length?=?0;?? ????int?position?=?0,?value?=?0;?? ????pNODE?head?=?NULL;?? ?? ????head?=?CreateSgCcLinkList();?? ?? ????flag?=?IsEmptySgCcLinkList(head);?? ????if?(flag)?? ????????printf("單向循環鏈表為空!\n");?? ????else?? ????{?? ????????length?=?GetLengthSgCcLinkList(head);?? ????????printf("單向循環鏈表的長度為:%d\n",?length);?? ????????TraverseSgCcLinkList(head);?? ????}?? ?? ????printf("請輸入要插入節點的位置和元素值(兩個數用空格隔開):");?? ????scanf("%d?%d",?&position,?&value);?? ????flag?=?InsertEleSgCcLinkList(head,?position,?value);?? ????if?(flag)?? ????{?? ????????printf("插入節點成功!\n");?? ????????TraverseSgCcLinkList(head);?? ????}????? ????else?? ????????printf("插入節點失敗!\n");?? ?? ????flag?=?IsEmptySgCcLinkList(head);?? ????if?(flag)?? ????????printf("單向循環鏈表為空,不能進行刪除操作!\n");?? ????else?? ????{?? ????????printf("請輸入要刪除節點的位置:");?? ????????scanf("%d",?&position);?? ????????flag?=?DeleteEleSgCcLinkList(head,?position);?? ????????if?(flag)?? ????????{?? ????????????printf("刪除節點成功!\n");?? ????????????TraverseSgCcLinkList(head);?? ????????}????? ????????else?? ????????????printf("刪除節點失敗!\n");?? ????}?? ?? ????FreeMemory(&head);?? ????if?(NULL?==?head)?? ????????printf("已成功刪除單向循環鏈表,釋放內存完成!\n");?? ????else?? ????????printf("刪除單向循環鏈表失敗,釋放內存未完成!\n");?? ?? ????return?0;?? }??
PS:數據結構的學習還在繼續,剛開始寫這個程序的時候,在釋放內存的時候碰到了一些問題,不過后面通過調試還是解決了。所以,我想說調試能力也是很重要的,因為調試過一篇,你對這個程序的原理也懂的差不多了。如果你們在看程序的時候發現錯誤,希望能積極指出來。
下一站是雙向鏈表。加油吧!
總結
以上是生活随笔為你收集整理的(C语言版)链表(二)——实现单向循环链表创建、插入、删除、释放内存等简单操作的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。