<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          認(rèn)識(shí)數(shù)據(jù)結(jié)構(gòu)之【鏈表】

          共 4245字,需瀏覽 9分鐘

           ·

          2021-04-23 00:29

          須彌零一

          認(rèn)識(shí)數(shù)據(jù)結(jié)構(gòu)之【鏈表】

          上篇文章介紹了數(shù)組,并且在文章末尾也簡(jiǎn)單的提了一句,有個(gè)東西和數(shù)組比較像 —— 鏈表。那么今天就接著來(lái)簡(jiǎn)單說(shuō)說(shuō)鏈表,錯(cuò)過(guò)往期文章的朋友可以點(diǎn)擊下面列表的鏈接查閱。

          認(rèn)識(shí)數(shù)據(jù)結(jié)構(gòu)系列往期文章:

          ?認(rèn)識(shí)數(shù)據(jù)結(jié)構(gòu)之【樹(shù)】?認(rèn)識(shí)數(shù)據(jù)結(jié)構(gòu)之【數(shù)組】

          回顧數(shù)組元素的訪問(wèn)

          上期文章中介紹了數(shù)組是一組相同類型的元素集合,并且這些元素在內(nèi)存中是按照下標(biāo)的先后順序連續(xù)存放的。我們也已經(jīng)知道,比如要訪問(wèn)數(shù)組 name 的第5個(gè)元素,我們可以使用下標(biāo)來(lái)獲取,例如 name[4]
          那么往微觀的角度看看,計(jì)算機(jī)是怎么通過(guò)這個(gè)下標(biāo)來(lái)獲取我們想要的元素呢?OK!咱們看以下的代碼片段:
          #include <stdio.h>int main(){    unsigned int numbers[] = {100, 200, 300, 400, 500};    printf("單個(gè)unsigned int所占字節(jié)數(shù):%d\n", sizeof(unsigned int));    printf("numbers數(shù)組所占字節(jié)數(shù):%d\n", sizeof(numbers));    printf("數(shù)組numbers的元素個(gè)數(shù):%d\n\n", sizeof(numbers) / sizeof(unsigned int));    printf("numbers的指針地址:0x%x\n\n", &numbers);    printf("元素numbers[0]的指針地址:0x%x\n", &numbers[0]);    printf("元素numbers[1]的指針地址:0x%x\n", &numbers[1]);    printf("元素numbers[2]的指針地址:0x%x\n", &numbers[2]);    printf("元素numbers[3]的指針地址:0x%x\n", &numbers[3]);    printf("元素numbers[4]的指針地址:0x%x\n", &numbers[4]);       return 0;}
          上面代碼的某一次執(zhí)行結(jié)果如下:
          單個(gè)unsigned int所占字節(jié)數(shù):4numbers數(shù)組所占字節(jié)數(shù):20數(shù)組numbers的元素個(gè)數(shù):5numbers的指針地址:0xc48df320元素numbers[0]的指針地址:0xc48df320元素numbers[1]的指針地址:0xc48df324元素numbers[2]的指針地址:0xc48df328元素numbers[3]的指針地址:0xc48df32c元素numbers[4]的指針地址:0xc48df330

          注:您自己運(yùn)行的結(jié)果地址應(yīng)該和上面是不一樣的。

          不管你自己的代碼運(yùn)行了幾次,你如果觀察仔細(xì)的話,應(yīng)該已經(jīng)看出來(lái)規(guī)律了:

          ?每個(gè) unsigned int 占四個(gè)字節(jié)?numbers 數(shù)組所占字節(jié)數(shù) = 單個(gè) unsigned int 所占字節(jié) * numbers 數(shù)組元素個(gè)數(shù)?數(shù)組 numbers 的內(nèi)存地址和 其第一個(gè)元素 numbers[0] 的地址相同?numbers 每?jī)蓚€(gè)相鄰元素的地址相差一個(gè) unsigned int 的長(zhǎng)度

          根據(jù)上面的運(yùn)行結(jié)果可知,numbers 數(shù)組在內(nèi)存中應(yīng)該是如下圖的樣子:

          綜上所述,因?yàn)閿?shù)組是相同類型數(shù)據(jù)的集合在內(nèi)存中順序存放的,并且我們已知某一個(gè)數(shù)組變量的內(nèi)存指針地址,則第N個(gè)元素的指針地址 = 數(shù)組的指針地址 + 單個(gè)元素所占的字節(jié)數(shù) * N 。知道了第N個(gè)元素的指針地址,則向后獲取單個(gè)元素所占字節(jié)的長(zhǎng)度,就獲取了這個(gè)元素的值。
          以上面的示例,如果我們想獲取 numbers[2] 的值,則可以通過(guò)如下方式獲取:

          numbers指針地址0xc48df320 + 單個(gè)unsigned int的長(zhǎng)度4 * 2 = 0xc48df320 + 8 = 0xc48df328
          內(nèi)存 [0xc48df328 , 0xc48df32c) 之間的數(shù)據(jù)就是 number[2] 的值

          OK!數(shù)組通過(guò)下標(biāo)取值就復(fù)習(xí)到這了,下面看看今天的主角——鏈表。

          鏈表

          鏈表的定義

          鏈表是一種物理存儲(chǔ)單元上非連續(xù)、非順序的存儲(chǔ)結(jié)構(gòu),數(shù)據(jù)元素的邏輯順序是通過(guò)鏈表中的指針鏈接次序?qū)崿F(xiàn)的。鏈表由一系列結(jié)點(diǎn)(鏈表中每一個(gè)元素稱為結(jié)點(diǎn))組成,結(jié)點(diǎn)可以在運(yùn)行時(shí)動(dòng)態(tài)生成。每個(gè)結(jié)點(diǎn)包括兩個(gè)部分:一個(gè)是存儲(chǔ)數(shù)據(jù)元素的數(shù)據(jù)域,另一個(gè)是存儲(chǔ)下一個(gè)結(jié)點(diǎn)地址的指針域。

          鏈表的特點(diǎn)

          鏈表相比于數(shù)組的順序結(jié)構(gòu),操作復(fù)雜。但由于鏈表不必須按順序存儲(chǔ),鏈表在插入的時(shí)候可以達(dá)到O(1)的復(fù)雜度,比數(shù)組快得多,但是查找一個(gè)節(jié)點(diǎn)或者訪問(wèn)特定編號(hào)的節(jié)點(diǎn)則需要O(n)的時(shí)間,而數(shù)組相應(yīng)的時(shí)間復(fù)雜度是O(1)。
          鏈表結(jié)構(gòu)可以克服數(shù)組需要預(yù)先知道數(shù)據(jù)大小的缺點(diǎn),鏈表結(jié)構(gòu)可以充分利用計(jì)算機(jī)內(nèi)存空間,實(shí)現(xiàn)靈活的內(nèi)存動(dòng)態(tài)管理。但是鏈表失去了數(shù)組隨機(jī)讀取的優(yōu)點(diǎn),同時(shí)鏈表由于增加了結(jié)點(diǎn)的指針域,空間開(kāi)銷比較大。鏈表最明顯的好處就是,常規(guī)數(shù)組排列關(guān)聯(lián)項(xiàng)目的方式可能不同于這些數(shù)據(jù)項(xiàng)目在記憶體或磁盤(pán)上順序,數(shù)據(jù)的存取往往要在不同的排列順序中轉(zhuǎn)換。鏈表允許插入和移除表上任意位置上的節(jié)點(diǎn),但是不允許隨機(jī)存取。

          鏈表的分類

          線性鏈表(單鏈表)和非線性鏈表

          ?由分別表示 結(jié)點(diǎn)1,結(jié)點(diǎn)2,…,結(jié)點(diǎn)N的N個(gè)結(jié)點(diǎn)依次相鏈構(gòu)成的鏈表,稱為線性表的鏈?zhǔn)酱鎯?chǔ)表示。由于此類鏈表的每個(gè)結(jié)點(diǎn)中只包含一個(gè)指針域,故又稱單鏈表線性鏈表?非線性的鏈表,可以參見(jiàn)相關(guān)的其他數(shù)據(jù)結(jié)構(gòu),例如樹(shù)、圖。對(duì)比線性鏈表的定義可知,非線性鏈表的每個(gè)結(jié)點(diǎn)可能會(huì)包含多個(gè)指針域。

          雙向鏈表

          雙向鏈表其實(shí)是單鏈表的改進(jìn)。
          當(dāng)我們對(duì)單鏈表進(jìn)行操作時(shí),有時(shí)你要對(duì)某個(gè)結(jié)點(diǎn)的直接前驅(qū)進(jìn)行操作時(shí),又必須從表頭開(kāi)始查找。這是由單鏈表結(jié)點(diǎn)的結(jié)構(gòu)所限制的。因?yàn)閱捂湵砻總€(gè)結(jié)點(diǎn)只有一個(gè)存儲(chǔ)直接后繼結(jié)點(diǎn)地址的鏈域,那么能不能定義一個(gè)既有存儲(chǔ)直接后繼結(jié)點(diǎn)地址的鏈域,又有存儲(chǔ)直接前驅(qū)結(jié)點(diǎn)地址的鏈域的這樣一個(gè)雙鏈域結(jié)點(diǎn)結(jié)構(gòu)呢?這就是雙向鏈表。
          在雙向鏈表中,結(jié)點(diǎn)除含有數(shù)據(jù)域外,還有兩個(gè)鏈域,一個(gè)存儲(chǔ)直接后繼結(jié)點(diǎn)地址,一般稱之為右鏈域;一個(gè)存儲(chǔ)直接前驅(qū)結(jié)點(diǎn)地址,一般稱之為左鏈域。

          循環(huán)鏈表

          循環(huán)鏈表是與單鏈表一樣,是一種鏈?zhǔn)降拇鎯?chǔ)結(jié)構(gòu),所不同的是,循環(huán)鏈表的最后一個(gè)結(jié)點(diǎn)的指針是指向該循環(huán)鏈表的第一個(gè)結(jié)點(diǎn)或者表頭結(jié)點(diǎn),從而構(gòu)成一個(gè)環(huán)形的鏈。
          循環(huán)鏈表的運(yùn)算與單鏈表的運(yùn)算基本一致。所不同的有以下幾點(diǎn):

          1.在建立一個(gè)循環(huán)鏈表時(shí),必須使其最后一個(gè)結(jié)點(diǎn)的指針指向表頭結(jié)點(diǎn),而不是象單鏈表那樣置為NULL。此種情況還使用于在最后一個(gè)結(jié)點(diǎn)后插入一個(gè)新的結(jié)點(diǎn)。2.在判斷是否到表尾時(shí),是判斷該結(jié)點(diǎn)鏈域的值是否是表頭結(jié)點(diǎn),當(dāng)鏈域值等于表頭指針時(shí),說(shuō)明已到表尾。而非象單鏈表那樣判斷鏈域值是否為NULL。

          循環(huán)鏈表的舉例:約瑟夫還問(wèn)題,感興趣的朋友可以自己查找相關(guān)資料了解一下。

          問(wèn)題來(lái)源:
               據(jù)說(shuō)著名猶太歷史學(xué)家Josephus有過(guò)以下的故事:在羅馬人占領(lǐng)喬塔帕特后,39 個(gè)猶太人與Josephus及他的朋友躲到一個(gè)洞中,39個(gè)猶太人決定寧愿死也不要被敵人抓到,于是決定了一個(gè)自殺方式,41個(gè)人排成一個(gè)圓圈,由第1個(gè)人開(kāi)始報(bào)數(shù),每報(bào)數(shù)到第3人該人就必須自殺,然后再由下一個(gè)重新報(bào)數(shù),直到所有人都自殺身亡為止。然而Josephus 和他的朋友并不想遵從。首先從一個(gè)人開(kāi)始,越過(guò)k-2個(gè)人(因?yàn)榈谝粋€(gè)人已經(jīng)被越過(guò)),并殺掉第k個(gè)人。接著,再越過(guò)k-1個(gè)人,并殺掉第k個(gè)人。這個(gè)過(guò)程沿著圓圈一直進(jìn)行,直到最終只剩下一個(gè)人留下,這個(gè)人就可以繼續(xù)活著。問(wèn)題是,給定了和,一開(kāi)始要站在什么地方才能避免被處決。Josephus要他的朋友先假裝遵從,他將朋友與自己安排在第16個(gè)與第31個(gè)位置,于是逃過(guò)了這場(chǎng)死亡游戲。

          鏈表的操作

          遍歷

          ?對(duì)于線性鏈表的遍歷很容易。因?yàn)槊總€(gè)結(jié)點(diǎn)上有指向下一個(gè)結(jié)點(diǎn)的指針域,通過(guò)指針可以很容易的遍歷完整個(gè)鏈表。?對(duì)于非線性鏈表的遍歷稍微復(fù)雜一些,因?yàn)槊總€(gè)結(jié)點(diǎn)指向下一個(gè)結(jié)點(diǎn)的指針域有多個(gè),這些多個(gè)指針域的遍歷順序不一樣則遍歷出來(lái)的結(jié)果也不一樣。此處不多說(shuō)了,關(guān)于樹(shù)的遍歷可以點(diǎn)擊文末關(guān)于樹(shù)的文章鏈接查看?對(duì)于循環(huán)鏈表來(lái)說(shuō),需要注意的是如何決定終止條件,而使遍歷不會(huì)變成一個(gè)死循環(huán)

          插入結(jié)點(diǎn)

          鏈表上插入結(jié)點(diǎn)的操作實(shí)際上就是操作指針域的。比如要在 結(jié)點(diǎn)A 和 結(jié)點(diǎn)C 之間插入 結(jié)點(diǎn)B,則僅僅需要把 結(jié)點(diǎn)A 的指針域指向 結(jié)點(diǎn)B,并且把 結(jié)點(diǎn)B 的指針域指向 結(jié)點(diǎn)C 即可。

          刪除結(jié)點(diǎn)

          刪除結(jié)點(diǎn)同插入結(jié)點(diǎn)一樣也是對(duì)指針域的操作。比如要將 A -> B -> C 這樣的鏈表中的 結(jié)點(diǎn)B 刪除僅僅需要將 結(jié)點(diǎn)A 的指針域指向 結(jié)點(diǎn)C 即可。結(jié)點(diǎn)B 指向 結(jié)點(diǎn)C 的指針域可以根據(jù)你的需要來(lái)決定是否刪除,不管刪除與否這都不影響在原來(lái)的鏈表中已經(jīng)移除了結(jié)點(diǎn)B。

          最后

          本篇文章從介紹數(shù)組的取值方式切入,對(duì)比介紹了鏈表的一些基本知識(shí)。但是對(duì)于鏈表的操作并沒(méi)有給出具體的示例,但這也是認(rèn)識(shí)數(shù)據(jù)結(jié)構(gòu)系列的宗旨:不過(guò)多的添加示例,希望通過(guò)抽象的模型來(lái)理解數(shù)據(jù)結(jié)構(gòu)。感興趣的你可以用自己擅長(zhǎng)的編程語(yǔ)言來(lái)實(shí)際實(shí)現(xiàn)一下如何操作鏈表,這樣你會(huì)記得更牢固,理解的更深入。

          大家下期見(jiàn)~(●ˇ?ˇ●)


          ---- END ----

          往期文章:

          ?認(rèn)識(shí)數(shù)據(jù)結(jié)構(gòu)之【樹(shù)】?認(rèn)識(shí)數(shù)據(jù)結(jié)構(gòu)之【數(shù)組】



          歡迎關(guān)注我的公眾號(hào)“須彌零一”,原創(chuàng)技術(shù)文章第一時(shí)間推送。


          瀏覽 74
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  色婷婷综合av | 无码性爱片 | 三级片网站入口 | 鸥美无毛人妖家庭乱伦视频 | 九色丨老熟女丨91啦 |