C語言實現(xiàn)雙向鏈表

目前我們所學到的鏈表筐高,無論是動態(tài)鏈表還是靜態(tài)鏈表,表中各節(jié)點中都只包含一個指針(游標)以舒,且都統(tǒng)一指向直接后繼節(jié)點,通常稱這類鏈表為單向鏈表(或單鏈表)慢哈。

雖然使用單鏈表能 100% 解決邏輯關系為 "一對一" 數據的存儲問題蔓钟,但在解決某些特殊問題時,單鏈表并不是效率最優(yōu)的存儲結構卵贱。比如說奋刽,如果算法中需要大量地找某指定結點的前趨結點瓦侮,使用單鏈表無疑是災難性的,因為單鏈表更適合 "從前往后" 找佣谐,而 "從后往前" 找并不是它的強項肚吏。

為了能夠高效率解決類似的問題,本篇文章我們一起來討論雙向鏈表(簡稱雙鏈表)狭魂。
從名字上理解雙向鏈表罚攀,即鏈表是 "雙向" 的,如下圖所示:

雙向,指的是各節(jié)點之間的邏輯關系是雙向的雌澄,但通常頭指針只設置一個斋泄,除非實際情況需要。

從上圖中可以看到镐牺,雙向鏈表中各節(jié)點包含以下 3 部分信息(如下圖 所示):

  • 指針域:用于指向當前節(jié)點的直接前驅節(jié)點炫掐;
  • 數據域:用于存儲數據元素。
  • 指針域:用于指向當前節(jié)點的直接后繼節(jié)點睬涧;

    因此募胃,雙鏈表的節(jié)點結構用 C 語言實現(xiàn)為:
typedef struct Node
{
    struct Node * prior;//指向直接前趨
    int data;
    struct Node * next;//指向直接后繼
}Node;

雙向鏈表的創(chuàng)建

同單鏈表相比,雙鏈表僅是各節(jié)點多了一個用于指向直接前驅的指針域畦浓。因此痹束,我們可以在單鏈表的基礎輕松實現(xiàn)對雙鏈表的創(chuàng)建。

需要注意的是讶请,與單鏈表不同祷嘶,雙鏈表創(chuàng)建過程中,每創(chuàng)建一個新節(jié)點夺溢,都要與其前驅節(jié)點建立兩次聯(lián)系论巍,分別是:

  1. 將新節(jié)點的 prior 指針指向直接前驅節(jié)點;
  2. 將直接前驅節(jié)點的 next 指針指向新節(jié)點风响;

這里給出創(chuàng)建雙向鏈表的 C 語言實現(xiàn)代碼:

Node* initNode(Node * head){
    head=(Node*)malloc(sizeof(Node));//創(chuàng)建鏈表第一個結點(首元結點)
    head->prior=NULL;
    head->next=NULL;
    head->data=1;
    Node * list=head;
    for (int i=2; i<=3; i++) {
        //創(chuàng)建并初始化一個新結點
        Node * body=(Node*)malloc(sizeof(Node));
        body->prior=NULL;
        body->next=NULL;
        body->data=i;
      
        list->next=body;//直接前趨結點的next指針指向新結點
        body->prior=list;//新結點指向直接前趨結點
        list=list->next;
    }
    return head;
}

我們可以嘗試著在 main 函數中輸出創(chuàng)建的雙鏈表环壤,C 語言代碼如下:

#include <stdio.h>
#include <stdlib.h>
//節(jié)點結構
typedef struct Node{
    struct Node * prior;
    int data;
    struct Node * next;
}Node;
//雙鏈表的創(chuàng)建函數
Node* initNode(Node * head);
//輸出雙鏈表的函數
void display(Node * head);

int main() {
    //創(chuàng)建一個頭指針
    Node * head=NULL;
    //調用鏈表創(chuàng)建函數
    head=initNode(head);
    //輸出創(chuàng)建好的鏈表
    display(head);
    //顯示雙鏈表的優(yōu)點
    printf("鏈表中第 4 個節(jié)點的直接前驅是:%d",head->next->next->next->prior->data);
    return 0;
}
Node* initNode(Node * head){
    //創(chuàng)建一個首元節(jié)點,鏈表的頭指針為head
    head=(Node*)malloc(sizeof(Node));
    //對節(jié)點進行初始化
    head->prior=NULL;
    head->next=NULL;
    head->data=1;
    //聲明一個指向首元節(jié)點的指針钞诡,方便后期向鏈表中添加新創(chuàng)建的節(jié)點
    Node * list=head;
    for (int i=2; i<=5; i++) {
        //創(chuàng)建新的節(jié)點并初始化
        Node * body=(Node*)malloc(sizeof(Node));
        body->prior=NULL;
        body->next=NULL;
        body->data=i;

        //新節(jié)點與鏈表最后一個節(jié)點建立關系
        list->next=body;
        body->prior=list;
        //list永遠指向鏈表中最后一個節(jié)點
        list=list->next;
    }
    //返回新創(chuàng)建的鏈表
    return head;
}
void display(Node * head){
    Node * temp=head;
    while (temp) {
        //如果該節(jié)點無后繼節(jié)點郑现,說明此節(jié)點是鏈表的最后一個節(jié)點
        if (temp->next==NULL) {
            printf("%d\n",temp->data);
        }else{
            printf("%d <-> ",temp->data);
        }
        temp=temp->next;
    }
}

程序運行結果:

1 <-> 2 <-> 3 <-> 4 <-> 5
鏈表中第 4 個節(jié)點的直接前驅是:3

雙向鏈表基本操作

下面繼續(xù)討論有關雙向鏈表的一些基本操作,即如何在雙向鏈表中添加荧降、刪除接箫、查找或更改數據元素。

創(chuàng)建好的雙向鏈表如下圖所示:


雙向鏈表添加節(jié)點

根據數據添加到雙向鏈表中的位置不同朵诫,可細分為以下 3 種情況:
添加至表頭
將新數據元素添加到表頭辛友,只需要將該元素與表頭元素建立雙層邏輯關系即可。

換句話說,假設新元素節(jié)點為 temp废累,表頭節(jié)點為 head邓梅,則需要做以下 2 步操作即可:

  1. temp->next=head; head->prior=temp;
  2. 將 head 移至 temp,重新指向新的表頭邑滨;

例如日缨,將新元素 7 添加至雙鏈表的表頭,則實現(xiàn)過程如下圖 所示:


添加至表的中間位置
同單鏈表添加數據類似掖看,雙向鏈表中間位置添加數據需要經過以下 2 個步驟匣距,如下圖 所示:

  1. 新節(jié)點先與其直接后繼節(jié)點建立雙層邏輯關系;
  2. 新節(jié)點的直接前驅節(jié)點與之建立雙層邏輯關系哎壳;


添加至表尾
與添加到表頭是一個道理毅待,實現(xiàn)過程如下(如下圖 所示):

  1. 找到雙鏈表中最后一個節(jié)點;
  2. 讓新節(jié)點與最后一個節(jié)點進行雙層邏輯關系归榕;

因此尸红,雙向鏈表添加數據的 C 語言代碼,參考代碼如下:

Node * insertNode(Node * head,int data,int add){
    //新建數據域為data的結點
    Node * temp=(Node*)malloc(sizeof(Node));
    temp->data=data;
    temp->prior=NULL;
    temp->next=NULL;
    //插入到鏈表頭刹泄,要特殊考慮
    if (add==1) {
        temp->next=head;
        head->prior=temp;
        head=temp;
    }else{
        Node * body=head;
        //找到要插入位置的前一個結點
        for (int i=1; i<add-1; i++) {
            body=body->next;
        }
        //判斷條件為真外里,說明插入位置為鏈表尾
        if (body->next==NULL) {
            body->next=temp;
            temp->prior=body;
        }else{
            body->next->prior=temp;
            temp->next=body->next;
            body->next=temp;
            temp->prior=body;
        }
    }
    return head;
}
雙向鏈表刪除節(jié)點

雙鏈表刪除結點時,只需遍歷鏈表找到要刪除的結點循签,然后將該節(jié)點從表中摘除即可。
例如疙咸,刪除上面圖中的元素2县匠,如下圖所示:


lxliX4.gif

]
雙向鏈表刪除節(jié)點的 C 語言實現(xiàn)代碼如下:

//刪除結點的函數,data為要刪除結點的數據域的值
Node * delNode(Node * head,int data){
    Node * temp=head;
    //遍歷鏈表
    while (temp) {
        //判斷當前結點中數據域和data是否相等撒轮,若相等乞旦,摘除該結點
        if (temp->data==data) {
            temp->prior->next=temp->next;
            temp->next->prior=temp->prior;
            free(temp);
            return head;
        }
        temp=temp->next;
    }
    printf("鏈表中無該數據元素");
    return head;
}
雙向鏈表查找節(jié)點

通常,雙向鏈表同單鏈表一樣题山,都僅有一個頭指針兰粉。因此,雙鏈表查找指定元素的實現(xiàn)同單鏈表類似顶瞳,都是從表頭依次遍歷表中元素玖姑。

C 語言實現(xiàn)代碼為:

//head為原雙鏈表,elem表示被查找元素
int selectElem(Node * head,int elem){
//新建一個指針t慨菱,初始化為頭指針 head
    Node * t=head;
    int i=1;
    while (t) {
        if (t->data==elem) {
            return i;
        }
        i++;
        t=t->next;
    }
    //程序執(zhí)行至此處焰络,表示查找失敗
    return -1;
}
雙向鏈表更改節(jié)點

更改雙鏈表中指定結點數據域的操作是在查找的基礎上完成的。實現(xiàn)過程是:通過遍歷找到存儲有該數據元素的結點符喝,直接更改其數據域即可闪彼。

實現(xiàn)此操作的 C 語言實現(xiàn)代碼如下:

//更新函數,其中协饲,add 表示更改結點在雙鏈表中的位置畏腕,newElem 為新數據的值
Node *amendElem(Node * p,int add,int newElem){
    Node * temp=p;
    //遍歷到被刪除結點
    for (int i=1; i<add; i++) {
        temp=temp->next;
    }
    temp->data=newElem;
    return p;
}

基本上寫到這里這篇關于C語言實現(xiàn)雙向鏈表的文章就結束了缴川,總的實現(xiàn)代碼已經push到github,喜歡的小伙伴歡迎Star描馅!傳送門把夸,小編如果有什么寫的不好的地方,歡迎大家留言提出來流昏,多多指教扎即,如果還想了解其他語言實現(xiàn)的數據結構的相關算法,歡迎來我的個人博客相逢了解更多喲况凉!明天繼續(xù)更新C++語言實現(xiàn)雙向鏈表谚鄙,堅持就是勝利!加油刁绒!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末闷营,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子知市,更是在濱河造成了極大的恐慌傻盟,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嫂丙,死亡現(xiàn)場離奇詭異娘赴,居然都是意外死亡,警方通過查閱死者的電腦和手機跟啤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門诽表,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人隅肥,你說我怎么就攤上這事竿奏。” “怎么了腥放?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵泛啸,是天一觀的道長。 經常有香客問我秃症,道長候址,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任种柑,我火速辦了婚禮宗雇,結果婚禮上,老公的妹妹穿的比我還像新娘莹规。我一直安慰自己赔蒲,他們只是感情好,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著舞虱,像睡著了一般欢际。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上矾兜,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天损趋,我揣著相機與錄音,去河邊找鬼椅寺。 笑死浑槽,一個胖子當著我的面吹牛,可吹牛的內容都是我干的返帕。 我是一名探鬼主播桐玻,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼荆萤!你這毒婦竟也來了镊靴?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤链韭,失蹤者是張志新(化名)和其女友劉穎偏竟,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體敞峭,經...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡敦捧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年瞬浓,在試婚紗的時候發(fā)現(xiàn)自己被綠了洼裤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辙售。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖骗村,靈堂內的尸體忽然破棺而出嫌褪,到底是詐尸還是另有隱情呀枢,我是刑警寧澤胚股,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站裙秋,受9級特大地震影響琅拌,放射性物質發(fā)生泄漏。R本人自食惡果不足惜摘刑,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一进宝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧枷恕,春花似錦党晋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽灾而。三九已至,卻和暖如春扳剿,著一層夾襖步出監(jiān)牢的瞬間旁趟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工庇绽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锡搜,地道東北人。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓瞧掺,卻偏偏與公主長得像耕餐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子夸盟,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內容

  • 這篇文章是關于利用C++模板的方式實現(xiàn)的雙向鏈表以及雙向鏈表的基本操作蛾方,在之前的博文C語言實現(xiàn)雙向鏈表中,已經給大...
    北徯閱讀 566評論 0 0
  • C語言的標準庫并沒有實現(xiàn)鏈表上陕,所以需要我們通過所學的知識來實現(xiàn)鏈表桩砰。先來看看雙向鏈表的定義,來源于百度百科释簿。 雙向...
    zippozeng閱讀 282評論 0 0
  • 目錄 1亚隅、屬性 2、鏈表和數組的區(qū)別 2.1庶溶、數組概述 2.2煮纵、數組和鏈表優(yōu)缺點 2.3、鏈表和數組的比較 3偏螺、單...
    我哈啊哈啊哈閱讀 2,805評論 1 41
  • 基本概念 鏈表的含義: 鏈表是一種用于存儲數據集合的數據結構行疏,具有以下屬性 相鄰元素之間通過指針相連 最后一個元素...
    古劍誅仙閱讀 1,006評論 0 3
  • 關于雙向鏈表的解釋就不多說了,書本上介紹的挺詳細的了套像,只需要記住每個節(jié)點有一個指向下一個節(jié)點的指針變量和指向前一個...
    小角色被占用閱讀 1,262評論 0 0