鏈表詳解(C語(yǔ)言版)

??鏈表和線性表相對(duì),指的是在物理內(nèi)存上并非相連線性存儲(chǔ)的一種數(shù)據(jù)結(jié)構(gòu)硫痰。鏈表中的每個(gè)元素都是分散存儲(chǔ)的衩婚。因?yàn)榉稚⒋鎯?chǔ),為了能夠體現(xiàn)出數(shù)據(jù)元素之間的邏輯關(guān)系效斑,每個(gè)數(shù)據(jù)元素在存儲(chǔ)的同時(shí)非春,要配備一個(gè)指針,用于指向它的直接后繼元素,即每一個(gè)數(shù)據(jù)元素都指向下一個(gè)數(shù)據(jù)元素(最后一個(gè)指向NULL(空))奇昙。

鏈表中數(shù)據(jù)元素的構(gòu)成

每個(gè)元素本身由兩部分組成:

  • 本身的信息护侮,稱為“數(shù)據(jù)域”
  • 指向直接后繼的指針储耐,稱為“指針域”羊初。
節(jié)點(diǎn)的構(gòu)成

這兩部分信息組成數(shù)據(jù)元素的存儲(chǔ)結(jié)構(gòu),稱之為“結(jié)點(diǎn)”弧岳。n個(gè)結(jié)點(diǎn)通過指針域相互鏈接凳忙,組成一個(gè)鏈表业踏。


含有n個(gè)節(jié)點(diǎn)的鏈表

上圖中禽炬,由于每個(gè)結(jié)點(diǎn)中只包含一個(gè)指針域,生成的鏈表又被稱為 線性鏈表單鏈表勤家。
鏈表中存放的不是基本數(shù)據(jù)類型腹尖,需要用結(jié)構(gòu)體自定義實(shí)現(xiàn):

typedef struct Link{
    char elem;//代表數(shù)據(jù)域
    struct Link * next;//代表指針域,指向直接后繼元素
}link;

頭結(jié)點(diǎn)伐脖、頭指針和首元結(jié)點(diǎn)

  • 頭結(jié)點(diǎn): 有時(shí)热幔,在鏈表的第一個(gè)結(jié)點(diǎn)之前會(huì)額外增設(shè)一個(gè)結(jié)點(diǎn),結(jié)點(diǎn)的數(shù)據(jù)域一般不存放數(shù)據(jù)(有些情況下也可以存放鏈表的長(zhǎng)度等信息)讼庇,此結(jié)點(diǎn)被稱為頭結(jié)點(diǎn)绎巨。

若頭結(jié)點(diǎn)的指針域?yàn)榭眨∟ULL),表明鏈表是空表蠕啄。頭結(jié)點(diǎn)對(duì)于鏈表來(lái)說场勤,不是必須的,在處理某些問題時(shí)歼跟,給鏈表添加頭結(jié)點(diǎn)會(huì)使問題變得簡(jiǎn)單和媳。

  • 首元結(jié)點(diǎn):鏈表中第一個(gè)元素所在的結(jié)點(diǎn),它是頭結(jié)點(diǎn)后邊的第一個(gè)結(jié)點(diǎn)哈街。
  • 頭指針:永遠(yuǎn)指向鏈表中第一個(gè)結(jié)點(diǎn)的位置(如果鏈表有頭結(jié)點(diǎn)留瞳,頭指針指向頭結(jié)點(diǎn);否則骚秦,頭指針指向首元結(jié)點(diǎn))她倘。

頭結(jié)點(diǎn)和頭指針的區(qū)別:頭指針是一個(gè)指針,頭指針指向鏈表的頭結(jié)點(diǎn)或者首元結(jié)點(diǎn)作箍;頭結(jié)點(diǎn)是一個(gè)實(shí)際存在的結(jié)點(diǎn)硬梁,它包含有數(shù)據(jù)域和指針域。兩者在程序中的直接體現(xiàn)就是:頭指針只聲明而沒有分配存儲(chǔ)空間蒙揣,頭結(jié)點(diǎn)進(jìn)行了聲明并分配了一個(gè)結(jié)點(diǎn)的實(shí)際物理內(nèi)存靶溜。

頭結(jié)點(diǎn)、首元結(jié)點(diǎn)和頭指針

注意:?jiǎn)捂湵碇锌梢詻]有頭結(jié)點(diǎn),但是不能沒有頭指針罩息!


鏈表的創(chuàng)建和遍歷

萬(wàn)事開頭難嗤详,初始化鏈表首先要做的就是創(chuàng)建鏈表的頭結(jié)點(diǎn)或者首元結(jié)點(diǎn)。創(chuàng)建的同時(shí)瓷炮,要保證有一個(gè)指針永遠(yuǎn)指向的是鏈表的表頭葱色,這樣做不至于丟失鏈表。
例如創(chuàng)建一個(gè)鏈表(1娘香,2苍狰,3,4):

link * initLink(){
    link * p=(link*)malloc(sizeof(link));//創(chuàng)建一個(gè)頭結(jié)點(diǎn)
    link * temp=p;//聲明一個(gè)指針指向頭結(jié)點(diǎn)烘绽,用于遍歷鏈表
    //生成鏈表
    for (int i=1; i<5; i++) {
        link *a=(link*)malloc(sizeof(link));
        a->elem=i;
        a->next=NULL;
        temp->next=a; //這里*temp是一個(gè)指向頭結(jié)點(diǎn)的指針淋昭,所以temp->next指的是頭結(jié)點(diǎn)的next域
        temp=temp->next;
    }
    return p;
}

這里是尾插法建立鏈表,建立鏈表有兩種方法:頭插法尾插法

頭插法和尾插法的區(qū)別


鏈表中查找某節(jié)點(diǎn)

一般情況下安接,鏈表只能通過頭結(jié)點(diǎn)或者頭指針進(jìn)行訪問翔忽,所以實(shí)現(xiàn)查找某結(jié)點(diǎn)最常用的方法就是對(duì)鏈表中的結(jié)點(diǎn)進(jìn)行逐個(gè)遍歷。

實(shí)現(xiàn)代碼:

int selectElem(link * p,int elem){
    link * t=p;
    int i=1;
    while (t->next) {
        t=t->next;
        if (t->elem==elem) {
            return i;
        }
        i++;
    }
    return -1;
}

更改某節(jié)點(diǎn)的數(shù)據(jù)域

直接遍歷鏈表盏檐,找到節(jié)點(diǎn)歇式,然后直接更改其數(shù)據(jù)域即可。
實(shí)現(xiàn)代碼:

//更新函數(shù)胡野,其中材失,pos表示更改結(jié)點(diǎn)在鏈表中的位置,newElem 為新的數(shù)據(jù)域的值
int *amendElem(link * p, int pos, int newElem){
    link * temp = p;
     temp=temp->next;//在遍歷之前硫豆,temp指向首元結(jié)點(diǎn)
    //遍歷到被刪除結(jié)點(diǎn)
    for (int i=1; i<pos; i++) {
        temp=temp->next;
    }
    temp->elem=newElem;
    return p;
}

向鏈表中插入結(jié)點(diǎn)

鏈表中插入頭結(jié)點(diǎn)龙巨,根據(jù)插入位置的不同,分為3種:

  • 插入到鏈表的首部够庙,也就是頭結(jié)點(diǎn)和首元結(jié)點(diǎn)中間恭应;
  • 插入到鏈表中間的某個(gè)位置;
  • 插入到鏈表最末端耘眨;
向鏈表中插入節(jié)點(diǎn)5

雖然插入位置有區(qū)別昼榛,都使用相同的插入手法。分為兩步剔难,如上圖所示:

  1. 將新結(jié)點(diǎn)的next指針指向插入位置后的結(jié)點(diǎn)胆屿;
  2. 將插入位置前的結(jié)點(diǎn)的next指針指向插入結(jié)點(diǎn);

提示:在做插入操作時(shí)偶宫,首先要找到插入位置的上一個(gè)結(jié)點(diǎn)非迹,圖4中,也就是找到結(jié)點(diǎn) 1纯趋,相應(yīng)的結(jié)點(diǎn) 2 可通過結(jié)點(diǎn) 1 的 next 指針表示憎兽,這樣冷离,先進(jìn)行步驟 1,后進(jìn)行步驟 2纯命,實(shí)現(xiàn)過程中不需要添加其他輔助指針西剥。
要先執(zhí)行1再2,不能顛倒亿汞,如果先執(zhí)行2瞭空,則后續(xù)節(jié)點(diǎn)就丟失了無(wú)法找到。

實(shí)現(xiàn)代碼:

link * insertElem(link * p,int elem,int add){
    link * temp=p;//創(chuàng)建臨時(shí)結(jié)點(diǎn)temp
    //首先找到要插入位置的上一個(gè)結(jié)點(diǎn)
    for (int i=1; i<add; i++) {
        if (temp==NULL) {
            printf("插入位置無(wú)效\n");
            return p;
        }
        temp=temp->next;
    }    
    //創(chuàng)建插入結(jié)點(diǎn)c
    link * c=(link*)malloc(sizeof(link));
    c->elem=elem;
    //向鏈表中插入結(jié)點(diǎn)
    c->next=temp->next;
    temp->next=c;
    return  p;
}

注意:首先要保證插入位置的可行性疗我,例如圖 5 中咆畏,原本只有 5 個(gè)結(jié)點(diǎn),插入位置可選擇的范圍為:1-6吴裤,如果超過6旧找,本身不具備任何意義,程序提示插入位置無(wú)效嚼摩。


從鏈表中刪除節(jié)點(diǎn)

當(dāng)需要從鏈表中刪除某個(gè)結(jié)點(diǎn)時(shí)钦讳,需要進(jìn)行兩步操作:

  • 將結(jié)點(diǎn)從鏈表中摘下來(lái);
  • 手動(dòng)釋放掉結(jié)點(diǎn),回收被結(jié)點(diǎn)占用的內(nèi)存空間;

使用malloc函數(shù)申請(qǐng)的空間枕面,一定要注意手動(dòng)free掉。否則在程序運(yùn)行的整個(gè)過程中缚去,申請(qǐng)的內(nèi)存空間不會(huì)自己釋放(只有當(dāng)整個(gè)程序運(yùn)行完了以后潮秘,這塊內(nèi)存才會(huì)被回收),造成內(nèi)存泄漏易结,別把它當(dāng)成是小問題枕荞。

實(shí)現(xiàn)代碼:

link * delElem(link * p,int add){
    link * temp=p;
    //temp指向被刪除結(jié)點(diǎn)的上一個(gè)結(jié)點(diǎn)
    for (int i=1; i<add; i++) {
        temp=temp->next;
    }
    link * del=temp->next;//單獨(dú)設(shè)置一個(gè)指針指向被刪除結(jié)點(diǎn),以防丟失
    temp->next=temp->next->next;//刪除某個(gè)結(jié)點(diǎn)的方法就是更改前一個(gè)結(jié)點(diǎn)的指針域
    free(del);//手動(dòng)釋放該結(jié)點(diǎn)搞动,防止內(nèi)存泄漏
    return p;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末躏精,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子鹦肿,更是在濱河造成了極大的恐慌矗烛,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件箩溃,死亡現(xiàn)場(chǎng)離奇詭異瞭吃,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)涣旨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門歪架,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人霹陡,你說我怎么就攤上這事和蚪≈棺矗” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵攒霹,是天一觀的道長(zhǎng)导俘。 經(jīng)常有香客問我,道長(zhǎng)剔蹋,這世上最難降的妖魔是什么旅薄? 我笑而不...
    開封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任凿宾,我火速辦了婚禮供炼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘稚照。我一直安慰自己矫付,他們只是感情好凯沪,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著买优,像睡著了一般妨马。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上杀赢,一...
    開封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天烘跺,我揣著相機(jī)與錄音,去河邊找鬼脂崔。 笑死滤淳,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的砌左。 我是一名探鬼主播脖咐,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼汇歹!你這毒婦竟也來(lái)了屁擅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤产弹,失蹤者是張志新(化名)和其女友劉穎派歌,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體取视,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡硝皂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了作谭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片稽物。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖折欠,靈堂內(nèi)的尸體忽然破棺而出贝或,到底是詐尸還是另有隱情吼过,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布咪奖,位于F島的核電站盗忱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏羊赵。R本人自食惡果不足惜趟佃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望昧捷。 院中可真熱鬧闲昭,春花似錦、人聲如沸靡挥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)跋破。三九已至簸淀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間毒返,已是汗流浹背租幕。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留饿悬,地道東北人令蛉。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像狡恬,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蝎宇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容