生活随笔
收集整理的這篇文章主要介紹了
(C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
http://blog.csdn.net/fisherwan/article/details/19760681
上午寫了下單向循環(huán)鏈表的程序,今天下午我把雙向鏈表的程序?qū)懲炅恕F鋵嶋p向鏈表和單向鏈表也是有很多相似的地方的,聽名字可以猜到,每個節(jié)點都包含兩個指針,一個指針指向上一個節(jié)點,一個指針指向下一個節(jié)點。這里有兩個特殊的地方,第一就是頭節(jié)點的一個指針指向NULL空指針(沒有前驅(qū)節(jié)點),第二就是尾節(jié)點的一個指針指向NULL指針(沒有后繼節(jié)點)。
我們可以看下雙向鏈表的示意圖(自己畫的比較難看):
所以,我們在編程序的時候,這兩個指針的控制就是我們的難點,因為我們始終要讓這個鏈表保持這樣的鏈接不管是在創(chuàng)建的時候、插入的時候、刪除的時候等,一定要讓節(jié)點的兩個指針指向正確的節(jié)點。下面我們來看下雙向鏈表的代碼。
DbLinkList.h? 頭文件——包含節(jié)點結(jié)構(gòu)的定義和各種操作函數(shù)的聲明。
[cpp]?view plain
?copy #ifndef?DOUBLY_LINKED_LIST_H?? #define?DOUBLY_LINKED_LIST_H?? ?? typedef?struct?Node?? {?? ????int?data;?? ????struct?Node?*pNext;?? ????struct?Node?*pPre;?? }NODE,?*pNODE;?? ?? ?? pNODE?CreateDbLinkList(void);?? ?? ?? void?TraverseDbLinkList(pNODE?pHead);?? ?? ?? int?IsEmptyDbLinkList(pNODE?pHead);?? ?? ?? int?GetLengthDbLinkList(pNODE?pHead);?? ?? ?? int?InsertEleDbLinkList(pNODE?pHead,?int?pos,?int?data);?? ?? ?? int?DeleteEleDbLinkList(pNODE?pHead,?int?pos);?? ?? ?? void?FreeMemory(pNODE?*ppHead);?? ?? #endif??
DbLinkList.cpp
雙向鏈表的源文件——包含了各種操作函數(shù)的定義。
(1)這部分是創(chuàng)建雙向鏈表,和單向鏈表很相似,但是呢,有些地方還是得注意,就是每創(chuàng)建一個節(jié)點的時候都要注意初始化它的兩個指針。
[cpp]?view plain
?copy #include?<stdio.h>?? #include?<stdlib.h>?? #include?"DbLinkList.h"?? ?? ?? pNODE?CreateDbLinkList(void)?? {?? ????int?i,?length?=?0,?data?=?0;?? ????pNODE?pTail?=?NULL,?p_new?=?NULL;?? ????pNODE?pHead?=?(pNODE)malloc(sizeof(NODE));?? ?? ????if?(NULL?==?pHead)?? ????{?? ????????printf("內(nèi)存分配失敗!\n");?? ????????exit(EXIT_FAILURE);?? ????}?? ?????? ????pHead->data?=?0;?? ????pHead->pPre?=?NULL;?? ????pHead->pNext?=?NULL;?? ????pTail?=?pHead;?? ?? ????printf("請輸入想要創(chuàng)建鏈表的長度:");?? ????scanf("%d",?&length);?? ?? ????for?(i=1;?i<length+1;?i++)?? ????{?? ????????p_new?=?(pNODE)malloc(sizeof(NODE));?? ?? ????????if?(NULL?==?p_new)?? ????????{?? ????????????printf("內(nèi)存分配失敗!\n");?? ????????????exit(EXIT_FAILURE);?? ????????}?? ?? ????????printf("請輸入第%d個元素的值:",?i);?? ????????scanf("%d",?&data);?? ?? ????????p_new->data?=?data;?? ????????p_new->pNext?=?NULL;?? ????????p_new->pPre?=?pTail;?? ????????pTail->pNext?=?p_new;?? ????????pTail?=?p_new;?? ????}?? ?? ????return?pHead;?? }??
(2)這部分是獲得雙向鏈表的信息,這里和單向鏈表基本一致,因為遍歷的時候只用到了一個指針。
[cpp]?view plain
?copy ?? void?TraverseDbLinkList(pNODE?pHead)?? {?? ????pNODE?pt?=?pHead->pNext;?? ?? ????printf("打印鏈表如:");?? ????while?(pt?!=?NULL)?? ????{?? ????????printf("%d?",?pt->data);?? ????????pt?=?pt->pNext;?? ????}?? ????putchar('\n');?? }?? ?? ?? int?IsEmptyDbLinkList(pNODE?pHead)?? {?? ????pNODE?pt?=?pHead->pNext;?? ?? ????if?(p?==?NULL)?? ????????return?1;?? ????else?? ????????return?0;?? }?? ?? ?? int?GetLengthDbLinkList(pNODE?pHead)?? {?? ????int?length?=?0;?? ????pNODE?pt?=?pHead->pNext;?? ?? ????while?(pt?!=?NULL)?? ????{?? ????????length++;?? ????????pt?=?pt->pNext;?? ????}?? ????return?length;?? }??
(3)這部分是向雙向鏈表插入節(jié)點,也跟單向鏈表很多相似的地方。我們先來看下插入節(jié)點時的示意圖:
從圖中可以看到,每次我們添加一個節(jié)點都有很多地方要調(diào)節(jié)的,也就是每個節(jié)點的那兩個指針,一定要認真仔細自己動手寫一遍,有可能有些細節(jié)就會出錯。這里有一個地方需要注意,是和單向鏈表不同的地方,單向鏈表在插入節(jié)點的時候不需要判斷最后一個節(jié)點是否為空,因為這不影響程序的結(jié)果,但是對于雙向鏈表就不一樣了,因為我們后面要用到最后一個節(jié)點的一個指針指向前一個節(jié)點,如果最后一個節(jié)點是空的話(就是程序中的pt),就不存在pt->pPre了,那么程序運行到這里時就會報錯,所以我們要加個判斷,判斷此時節(jié)點是NULL的話就不需要控制它的指針了。
[cpp]?view plain
?copy ?? int?InsertEleDbLinkList(pNODE?pHead,?int?pos,?int?data)?? {?? ????pNODE?pt?=?NULL,?p_new?=?NULL;?? ?? ????if?(pos?>?0?&&?pos?<?GetLengthDbLinkList(pHead)+2)?? ????{?? ????????p_new?=?(pNODE)malloc(sizeof(NODE));?? ?? ????????if?(NULL?==?p_new)?? ????????{?? ????????????printf("內(nèi)存分配失敗!\n");?? ????????????exit(EXIT_FAILURE);?? ????????}?? ?? ????????while?(1)?? ????????{?? ????????????pos--;?? ????????????if?(0?==?pos)?? ????????????????break;?? ????????????pHead?=?pHead->pNext;?? ????????}?? ?????????? ????????pt?=?pHead->pNext;?? ????????p_new->data?=?data;?? ????????p_new->pNext?=?pt;?? ????????if?(NULL?!=?pt)?? ????????????pt->pPre?=?p_add;?? ????????p_new->pPre?=?pHead;?? ????????pHead->pNext?=?p_new;?? ?????????? ????????return?1;?? ????}?? ????else?? ????????return?0;?? }??
(4)這部分是從鏈表中刪除節(jié)點,當然這里和單向鏈表差不多,要注意的地方和插入節(jié)點時是一樣的,上面已經(jīng)說明了。
[cpp]?view plain
?copy ?? int?DeleteEleDbLinkList(pNODE?pHead,?int?pos)?? {?? ????pNODE?pt?=?NULL;?? ?? ????if?(pos?>?0?&&?pos?<?GetLengthDbLinkList(pHead)?+?1)?? ????{?? ????????while?(1)?? ????????{?? ????????????pos--;?? ????????????if?(0?==?pos)?? ????????????????break;?? ????????????pHead?=?pHead->pNext;?? ????????}?? ?? ????????pt?=?pHead->pNext->pNext;?? ????????free(pHead->pNext);?? ????????pHead->pNext?=?pt;?? ????????if?(NULL?!=?pt)?? ????????????pt->pPre?=?pHead;?? ?? ????????return?1;?? ????}?? ????else?? ????????return?0;?? }??
(5)這部分是用來釋放內(nèi)存的,注意的地方和上面一樣。
[cpp]?view plain
?copy ?? void?FreeMemory(pNODE?*ppHead)?? {?? ????pNODE?pt?=?NULL;?? ?? ????while?(*ppHead?!=?NULL)?? ????{?? ????????pt?=?(*ppHead)->pNext;?? ????????free(*ppHead);?? ????????if?(NULL?!=?pt)?? ????????????pt->pPre?=?NULL;?? ????????*ppHead?=?pt;?? ????}?? }??
main.cpp
測試程序源文件——通過簡單的交互信息來測試各個函數(shù)功能是否正確。
[cpp]?view plain
?copy #include?<stdio.h>?? #include?<stdlib.h>?? #include?"DbLinkList.h"?? ?? int?main(void)?? {?? ????int?flag?=?0,?length?=?0;?? ????int?position?=?0,?value?=?0;?? ????pNODE?head?=?NULL;?? ?? ????head?=?CreateDbLinkList();?? ?? ????flag?=?IsEmptyDbLinkList(head);?? ????if?(flag)?? ????????printf("雙向鏈表為空!\n");?? ????else?? ????{?? ????????length?=?GetLengthDbLinkList(head);?? ????????printf("雙向鏈表的長度為:%d\n",?length);?? ????????TraverseDbLinkList(head);?? ????}?? ?? ????printf("請輸入要插入節(jié)點的位置和元素值(兩個數(shù)用空格隔開):");?? ????scanf("%d?%d",?&position,?&value);?? ????flag?=?InsertEleDbLinkList(head,?position,?value);?? ????if?(flag)?? ????{?? ????????printf("插入節(jié)點成功!\n");?? ????????TraverseDbLinkList(head);?? ????}????? ????else?? ????????printf("插入節(jié)點失敗!\n");?? ?? ????flag?=?IsEmptyDbLinkList(head);?? ????if?(flag)?? ????????printf("雙向鏈表為空,不能進行刪除操作!\n");?? ????else?? ????{?? ????????printf("請輸入要刪除節(jié)點的位置:");?? ????????scanf("%d",?&position);?? ????????flag?=?DeleteEleDbLinkList(head,?position);?? ????????if?(flag)?? ????????{?? ????????????printf("刪除節(jié)點成功!\n");?? ????????????TraverseDbLinkList(head);?? ????????}????? ????????else?? ????????????printf("刪除節(jié)點失敗!\n");?? ????}?? ?? ????FreeMemory(&head);?? ????if?(NULL?==?head)?? ????????printf("已成功刪除雙向鏈表,釋放內(nèi)存完成!\n");?? ????else?? ????????printf("刪除雙向鏈表失敗,釋放內(nèi)存未完成!\n");?? ?? ????return?0;?? }??
PS:相信對很多人來說鏈表的相關(guān)知識其實不難,很快能把這個程序編出來。但是還是有很多細節(jié)的問題要自己編過才知道的,我自己在學習的過程中就遇到過,所以我不讓大家再走彎路。
總結(jié)
以上是生活随笔為你收集整理的(C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。