一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

以后再也不怕別人問「單鏈表」的問題啦

算法與數(shù)據(jù)結(jié)構(gòu) ? 來源:未知 ? 作者:李倩 ? 2018-11-23 11:30 ? 次閱讀

寫在之前

在程序設(shè)計里,我們經(jīng)常需要將同為某個類型的一組數(shù)據(jù)元素作為一個整體來使用,需要創(chuàng)建這種元素組,用變量來記錄它們或者傳入函數(shù)等等等等,「線性表」就是這樣一組元素的抽象,它是某類元素的集合并且記錄著元素之間一種順序關(guān)系,是最基本的數(shù)據(jù)結(jié)構(gòu)之一,在實際程序中運(yùn)用非常廣泛,比如 Python 中的 list 和 tuple 都可以看作是線性表的實現(xiàn)。

基于各種實際操作等方面的綜合考慮,我們提出了兩種實現(xiàn)線性表的形式:「順序表」和「鏈表」。

「順序表」是將表中的元素順序存放在一大塊連續(xù)的存儲區(qū)間里,所以在這里元素間的順序是由它們的存儲順序來表示的。「鏈表」則是將表中元素存放在一系列的結(jié)點中(結(jié)點的存儲位置可以是連續(xù)的,可以是不連續(xù)的,也就意味著它們可以存在任何內(nèi)存未被占用的位置),這些結(jié)點通過連接構(gòu)造起來,結(jié)點分為「數(shù)據(jù)域」和「指針域」。這次我們要學(xué)習(xí)的「單鏈表」就是「鏈表」的一種實現(xiàn)形式,「數(shù)據(jù)域」保存著作為表元素的數(shù)據(jù)項,「指針域」保存同一個表里的下一個結(jié)點的標(biāo)識。

在正式說「單鏈表」之前,我先來說一下很多人在學(xué)習(xí)鏈表之初都傻傻分不清的兩個東西:「頭結(jié)點」和「頭指針」。

「頭結(jié)點」的設(shè)立是為了操作的統(tǒng)一和方便,是放在第一個元素的節(jié)點之前,它的數(shù)據(jù)域一般沒有意義,并且它本身也不是鏈表必須要帶的。那設(shè)立頭節(jié)點的目的是什么呢?其實就是為了在某些時候可以更方便的對鏈表進(jìn)行操作,有了頭結(jié)點,我們在對第一個元素前插入或者刪除結(jié)點的時候,它的操作與其它結(jié)點的操作就統(tǒng)一了。

「頭指針」顧名思義,是指向鏈表第一個結(jié)點的指針,如果有頭結(jié)點的話,那么就是指向頭結(jié)點的指針。它是鏈表的必備元素且無論鏈表是否為空,頭指針都不能為空,因為在訪問鏈表的時候你總得知道它在什么位置,這樣才能通過它的指針域找到下一個結(jié)點的位置,也就是說知道了頭指針,整個鏈表的元素我們都是可以訪問的,所以它必須要存在,這也就是我們常說的「標(biāo)識」,這也就是為什么我們一般用頭指針來表示鏈表。

單鏈表

n 個結(jié)點鏈接成一個鏈表,這也就是平時書上所說的「鏈?zhǔn)酱鎯Y(jié)構(gòu)」,因為這個鏈表中的每個結(jié)點中只包含一個指針域,所以又叫「單鏈表」。單鏈表正是通過每個結(jié)點的指針域?qū)⒕€性表的數(shù)據(jù)元素按其邏輯次序鏈接在一起。單鏈表的第一個結(jié)點的存儲位置叫做「頭指針」,最后一個結(jié)點的指針為「空」,一般用 “^” 表示。

上圖是不帶頭結(jié)點的單鏈表,下面我們來看一下帶頭結(jié)點的單鏈表:

還有一種是空鏈表:

通過上面 3 個圖我們發(fā)現(xiàn)無論單鏈表是否為空,是否有頭結(jié)點,頭指針都是存在的,這就很好的印證了之前我們所說的「頭指針是鏈表的必備元素且無論鏈表是否為空,頭指針都不能為空」。

為了方便后續(xù)的操作,我們一般會先定義一個簡單的結(jié)點類:

class Node(object): def __init__(self,data): self.data = data self.next = None

單鏈表的基本操作

首先我們先來創(chuàng)建一個鏈表類:

class LinkList(object): def __init__(self): self.head = Node(None) # 判斷鏈表是否為空 def IsEmpty(self): p = self.head # 頭指針 if p.next == None: print("List is Empty") return True return False # 打印鏈表 def PrintList(self): if self.IsEmpty(): return False p = self.head while p: print(p.data,end=' ') p = p.next

1.創(chuàng)建單鏈表

創(chuàng)建單鏈表的過程其實就是一個動態(tài)生成鏈表的過程,說簡單點就是從一個「空鏈表」開始,依次建立各個元素的結(jié)點,并把它們逐個插入鏈表,時間復(fù)雜度為 O(n):

def InitList(self,data): self.head = Node(data[0]) # 頭結(jié)點 p = self.head # 頭指針 for i in data[1:]: node = Node(i) p.next = node p = p.next

下面我們來測試一下:

# testlst = LinkList()data = [1, 4, 5, 8, 2, 3]lst.InitList(data)lst.PrintList()

輸出結(jié)果如下:

1 4 5 8 2 3

2.計算單鏈表的長度

在使用鏈表的時候,經(jīng)常需要求表的長度,為此我們可以創(chuàng)建一個球表長的函數(shù),這個函數(shù)就是從左到右掃描,遍歷表中的所有結(jié)點并完成計數(shù),時間復(fù)雜度為 O(n):

def LengthList(self): if self.IsEmpty(): return 0 p = self.head cnt = 0 while p: cnt += 1 p = p.next return cnt

下面我們來測試一下:

# testlst = LinkList()data = [1, 4, 5, 8, 2, 3]lst.InitList(data)print(lst.LengthList())

輸出的結(jié)果如下:

6

3.單鏈表的插入

假設(shè)我們要將結(jié)點 s 插入到 結(jié)點 p 的后面,只需要將結(jié)點 s 插入到結(jié)點 p 和 結(jié)點 p.next 之間即可,說起來簡單,那么到底如何插入呢?請看下圖:

由上圖我們可以看到,單鏈表結(jié)點的插入根本不需要驚動其它結(jié)點,只需要讓 s.next 和 p.next 的指針稍作改變即可。讓 p 的后繼結(jié)點改為 s 的后繼結(jié)點,再把 s 的后繼結(jié)點變成 p 的后繼結(jié)點。這里一定要切記,插入操作的順序不能改變,至于為什么,你可以拿起紙筆手動的畫一下,結(jié)果一下子就會出來(對于單鏈表的表頭和表尾的特殊情況,操作是相同的)。

# 單鏈表的插入(在第 s 個結(jié)點后面插入 data)def InsertList(self,s,data): if self.IsEmpty() or s < 0 or s > self.LengthList(): print("Insert failed!") return p = self.head index = 1 while index < s: ? ? ? ?p = p.next ? ? ? ?index += 1 ? ?node = Node(data) ? ?node.next = p.next ? ?p.next = node

下面我們來測試一下:

# testlst = LinkList()data = [1, 4, 5, 8, 2, 3]lst.InitList(data)lst.InsertList(0,666)lst.PrintList()

輸出的結(jié)果如下:

1 666 4 5 8 2 3

4.單鏈表刪除

看完插入,我們現(xiàn)在再來看看單鏈表的刪除。假設(shè)我們想要刪除一個結(jié)點 q,其實就是將它的前繼結(jié)點 p 的指針繞過 q,直接指向 q 的后繼結(jié)點即可,具體操作如下圖所示:

由上圖可以看出,我們只需要一步就可以實現(xiàn)刪除操作,那就是讓 p.next 直接為 p 的 next 的 next,p 的 next 為 q,所以也就是 p.next = q.next,時間復(fù)雜度為 O(n)。

# 單鏈表的刪除(刪除第 s 個結(jié)點)def DeleteList(self, s): if self.IsEmpty() or s < 0 or s > self.LengthList(): print("Delete failed! ") return p = self.head index = 1 while index < s: ? ? ? ?pre = p ? ? ? ?index += 1 ? ? ? ?p = p.next ? ?pre.next = p.next ? ?p = None

由 p = None 可以看出,在 Python 中,只需要簡單的將指針賦值為 None,就拋棄了鏈表原有的結(jié)點,Python 解釋器的存儲管理系統(tǒng)會自動回收不用的存儲。

下面我們來測試一下:

# testlst = LinkList()data = [1, 4, 5, 8, 2, 3]lst.InitList(data)lst.DeleteList(3)lst.PrintList()

輸出的結(jié)果如下:

1 4 8 2 3

5.單鏈表的讀取

在順序結(jié)構(gòu)中,我們想要獲取任意一個元素的存儲位置是很容易的,但是在單鏈表中,第 i 個元素到底在哪我們一開始沒辦法知道,只能傻傻的從頭開始找,所以在對于單鏈表獲取第 i 個元素的操作,算法上相對麻煩一些。

# 單鏈表的讀?。ǐ@取第 s 個結(jié)點的值)def GetList(self, s): if self.IsEmpty() or s < 0 or s > self.LengthList(): print("Read failed! ") return p = self.head index = 1 while index < s: ? ? ? ?index += 1 ? ? ? ?p = p.next ? ?print("第 {} 個值為 {}".format(s, p.data))

從上面的代碼我們可以很清楚的看出,單鏈表獲取第 i 個元素就是從頭開始找,知道第 i 個元素為止,所以我們可以很容易的估算出它的時間復(fù)雜度是 O(n)。任何事物都不是完美的,有好的地方就有壞的地方,元素的讀取就是單鏈表美中不足的地方之一。

寫在之后

單鏈表的操作其實還有不少,我只是寫了其中常用的幾種,希望大家能自己動手嘗試一下,把這幾個搞懂搞透。碰到這樣的問題從哪個方面去思考,如何去做才是最重要的,只有學(xué)會了這些,你在日后碰到相關(guān)問題的時候就知道如何去下手。

我在上面每個操作的講解中大多數(shù)給出了圖,通過圖來看解法題目了然。算法這個東西其實就是這樣,多動手實現(xiàn)以下,想不明白了就動手畫一下,畫著畫著思路就出來了。

最后我們就來總結(jié)一下鏈表操作的時間復(fù)雜度,如果你還不會估算算法的時間復(fù)雜度,請看我的循序漸進(jìn)帶你學(xué)習(xí)時間復(fù)雜度和空間復(fù)雜度。

創(chuàng)建空表 O(1)。

創(chuàng)建單鏈表 O(n)

插入元素:首端插入為 O(1);尾端插入為 O(n),因為還要找到表的最后結(jié)點;定位插入 為O(n)。

刪除元素:首端刪除為 O(1);尾端刪除為 O(n),理由如上;定位刪除為 O(n)。

以下是上述所有操作的代碼匯總:

# 結(jié)點類class Node(object): def __init__(self,data): self.data = data self.next = None# 鏈表類class LinkList(object): def __init__(self): self.head = Node(None) # 判斷鏈表是否為空 def IsEmpty(self): p = self.head # 頭指針 if p.next == None: print("List is Empty") return True return False # 打印鏈表 def PrintList(self): if self.IsEmpty(): return False p = self.head while p: print(p.data,end= ' ') p = p.next # 創(chuàng)建單鏈表 def InitList(self,data): self.head = Node(data[0]) # 頭結(jié)點 p = self.head # 頭指針 for i in data[1:]: node = Node(i) p.next = node p = p.next # 單鏈表的長度 def LengthList(self): if self.IsEmpty(): return 0 p = self.head cnt = 0 while p: cnt += 1 p = p.next return cnt # 單鏈表的插入(在第 s 個結(jié)點后面插入 data) def InsertList(self,s,data): if self.IsEmpty() or s < 0 or s > self.LengthList(): print("Insert failed!") return p = self.head index = 1 while index < s: ? ? ? ? ? ?p = p.next ? ? ? ? ? ?index += 1 ? ? ? ?node = Node(data) ? ? ? ?node.next = p.next ? ? ? ?p.next = node ? ?# 單鏈表的刪除(刪除第 s 個結(jié)點) ? ?def DeleteList(self, s): ? ? ? ?if self.IsEmpty() or s < 0 or s > self.LengthList(): print("Delete failed! ") return p = self.head index = 1 while index < s: ? ? ? ? ? ?pre = p ? ? ? ? ? ?index += 1 ? ? ? ? ? ?p = p.next ? ? ? ?pre.next = p.next ? ? ? ?p = None ? ?# 單鏈表的讀?。ǐ@取第 s 個結(jié)點的值) ? ?def GetList(self, s): ? ? ? ?if self.IsEmpty() or s < 0 or s > self.LengthList(): print("Read failed! ") return p = self.head index = 1 while index < s: ? ? ? ? ? ?index += 1 ? ? ? ? ? ?p = p.next ? ? ? ?print("第 {} 個值為 {}".format(s, p.data))

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 單鏈表
    +關(guān)注

    關(guān)注

    0

    文章

    13

    瀏覽量

    6976
  • 鏈表
    +關(guān)注

    關(guān)注

    0

    文章

    80

    瀏覽量

    10762

原文標(biāo)題:以后再也不怕別人問「單鏈表」的問題啦。

文章出處:【微信號:TheAlgorithm,微信公眾號:算法與數(shù)據(jù)結(jié)構(gòu)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦
    熱點推薦

    數(shù)據(jù)結(jié)構(gòu):鏈表的排序

    給定一個鏈表的頭結(jié)點head(該結(jié)點有值),長度為n的無序鏈表,對其按升序排序后,返回新鏈表。如當(dāng)輸入
    的頭像 發(fā)表于 11-30 13:56 ?1786次閱讀
    數(shù)據(jù)結(jié)構(gòu):<b class='flag-5'>單</b><b class='flag-5'>鏈表</b>的排序

    3D打印,又創(chuàng)新奇。媽媽再也不用擔(dān)心我亂丟鉛筆。...

    支。那天在某論壇找到一個筆筒的STL文件,覺得很好看,就用機(jī)器試了一下,嘻嘻。。果然很漂亮。再也不用擔(dān)心找不到筆了,而且放在桌上還是一道美麗的風(fēng)景線呢。跟大家分享一下哈。。很漂亮。真的不是蓋的,哇咔咔。。。開心,我的桌子更加漂亮干凈咯。越來越喜歡我的機(jī)器,也越來越佩服自
    發(fā)表于 12-02 15:37

    Compass打破次元壁,哆A夢新法寶

    compass差點“慘遭毒嘴”?。。?!Compass再也不能保持沉默Compass納入百寶袋條件一:只有34g,夠小夠輕便,不占“百寶袋”地方,無負(fù)荷攜帶。納入百寶袋條件二:小身板卻能超長待機(jī),就算長期蹲在
    發(fā)表于 01-30 09:51

    2016年1月參加分享資料獲得獎品

    `2016年1月參加分享資料獲得獎品,好豐盛的大餐,很喜歡那個秤,手感不錯,以后再也不怕吃多了看官們,上菜了1.包裝很整齊干凈,感謝QQ185XX3980,工作認(rèn)真,態(tài)度好,點個贊2.來個全家福,兩份禮品哦3.我喜歡的秤“媽媽再也不
    發(fā)表于 03-17 21:44

    兌換的哈爾斯口杯-抵抗寒冷再也不怕

    ` 本帖最后由 andyyau 于 2016-10-18 21:12 編輯 最近天氣逐漸變冷,發(fā)現(xiàn)自己的水杯放一晚水后早上不怎么熱了,用了幾年了,改退役了。正好兌換一個新杯子,冬天再也不用喝涼水
    發(fā)表于 10-18 21:11

    燒錄失敗導(dǎo)致boot無法加載的解決措施,再也不怕燒成磚了

    單獨燒寫fastboot,然后再來擦除boot即可重新執(zhí)行燒系統(tǒng)鏡像操作,如下圖:到此,板子就又恢復(fù)正常了,后面可以放心燒錄系統(tǒng)了,再也不用擔(dān)心板子成磚了
    發(fā)表于 03-03 11:45

    鏈表的缺陷是什么

    鏈表有一定的缺陷,就是單向性,只能從一個結(jié)點到下一個節(jié)點,而不能訪問到上一個結(jié)點,而循環(huán)鏈表就可以解決這一問題,當(dāng)然,用雙向鏈表更加方便#include #include typed
    發(fā)表于 07-14 08:09

    C語言實現(xiàn)鏈表舉例

    所謂鏈表,就是用一組任意的存儲單元存儲線性表元素的一種數(shù)據(jù)結(jié)構(gòu)。鏈表又分為鏈表、雙向鏈表和循環(huán)鏈表
    發(fā)表于 07-11 16:40 ?87次下載
    C語言實現(xiàn)<b class='flag-5'>單</b><b class='flag-5'>鏈表</b>舉例

    利用機(jī)器學(xué)習(xí)在15分鐘內(nèi)破解驗證碼,再也不擔(dān)心買不到12306的票

    再也不用輸入驗證碼了!
    的頭像 發(fā)表于 03-06 17:00 ?6714次閱讀
    利用機(jī)器學(xué)習(xí)在15分鐘內(nèi)破解驗證碼,<b class='flag-5'>再也不</b>擔(dān)心買不到12306的票<b class='flag-5'>啦</b>

    鏈表學(xué)習(xí)的超詳細(xì)說明(二)

    昨天跟大家分享了鏈表的一些基本用法,今天接著繼續(xù)和大家分享鏈表的用法,今天分享完,鏈表的操
    的頭像 發(fā)表于 12-24 17:33 ?910次閱讀

    有了這款 GitHub 開源神器,以后再也不怕找不到電影資源!

    “ 閱讀本文大概需要 3 分鐘。 ”大家好。相信各位都知道,平時上網(wǎng)找電影是個挺費時費力的活,為了要找到清晰度高、無水印、多音軌、多語言字幕的電影,經(jīng)常需要在幾個網(wǎng)站平臺來回切換,互相對...
    發(fā)表于 01-10 11:12 ?0次下載
    有了這款 GitHub 開源神器,<b class='flag-5'>以后</b><b class='flag-5'>再也不怕</b>找不到電影資源<b class='flag-5'>啦</b>!

    牢記以下幾點 再也不怕買到劣質(zhì)光纖跳線

    光纖是一種利用光在玻璃或塑料纖維中的全反射而制成的光傳導(dǎo)媒介,由于其頻率、帶寬大,損耗低,已成為現(xiàn)代信息傳輸領(lǐng)域中的最佳工具,為了幫助大家正確選擇產(chǎn)品,牢記以下幾點 再也不怕買到劣質(zhì)光纖跳線。
    的頭像 發(fā)表于 12-05 09:44 ?1311次閱讀

    醫(yī)療廢物在線監(jiān)管系統(tǒng)醫(yī)院再也不怕醫(yī)廢丟失了

    醫(yī)療廢物在線監(jiān)管系統(tǒng)醫(yī)院再也不怕醫(yī)廢丟失了 《醫(yī)療廢物分類目錄》將醫(yī)療廢物分為六類:感染性廢物、病理性廢物、損傷性廢物、藥物性廢物和化學(xué)性廢物。醫(yī)療機(jī)構(gòu)和醫(yī)療廢物集中處置單位在收集和處置醫(yī)療廢物
    的頭像 發(fā)表于 06-01 17:09 ?687次閱讀
    醫(yī)療廢物在線監(jiān)管系統(tǒng)醫(yī)院<b class='flag-5'>再也不怕</b>醫(yī)廢丟失了

    鏈表和雙鏈表的區(qū)別在哪里

    鏈表和雙鏈表的區(qū)別 鏈表的每一個節(jié)點中只有指向下一個結(jié)點的指針,不能進(jìn)行回溯。 雙鏈表的每一
    的頭像 發(fā)表于 07-27 11:20 ?1989次閱讀
    <b class='flag-5'>單</b><b class='flag-5'>鏈表</b>和雙<b class='flag-5'>鏈表</b>的區(qū)別在哪里

    實用的單片機(jī)接反電路,再也不怕電源接反了

    實用的單片機(jī)接反電路,再也不怕電源接反了
    的頭像 發(fā)表于 10-17 17:32 ?1326次閱讀
    實用的單片機(jī)接反電路,<b class='flag-5'>再也不怕</b>電源接反了