日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

(C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作

發(fā)布時間:2023/11/30 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (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;??
  • ??
  • //創(chuàng)建雙向鏈表??
  • pNODE?CreateDbLinkList(void);??
  • ??
  • //打印鏈表??
  • void?TraverseDbLinkList(pNODE?pHead);??
  • ??
  • //判斷鏈表是否為空??
  • int?IsEmptyDbLinkList(pNODE?pHead);??
  • ??
  • //計算鏈表長度??
  • int?GetLengthDbLinkList(pNODE?pHead);??
  • ??
  • //向鏈表插入節(jié)點??
  • int?InsertEleDbLinkList(pNODE?pHead,?int?pos,?int?data);??
  • ??
  • //從鏈表刪除節(jié)點??
  • int?DeleteEleDbLinkList(pNODE?pHead,?int?pos);??
  • ??
  • //刪除整個鏈表,釋放內(nèi)存??
  • 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"??
  • ??
  • //創(chuàng)建雙向鏈表??
  • 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
  • //向雙向鏈表中插入節(jié)點??
  • 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
  • //從鏈表中刪除節(jié)點??
  • 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
  • //刪除整個鏈表,釋放內(nèi)存??
  • 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)容還不錯,歡迎將生活随笔推薦給好友。