鏈表介紹及python的實(shí)現(xiàn)

鏈表是線性表的一種實(shí)現(xiàn)方式,它的基本想法是:

  • 將表中的元素分別存放在各個(gè)獨(dú)立的存儲(chǔ)區(qū)內(nèi)飞蛹,存儲(chǔ)區(qū)又稱為結(jié)點(diǎn)谤狡;
  • 在表中,可以通過(guò)任意結(jié)點(diǎn)找到與之相關(guān)的下一個(gè)結(jié)點(diǎn)桩皿;
  • 在前一個(gè)結(jié)點(diǎn)上豌汇,通過(guò)鏈接的方式記錄與下一個(gè)結(jié)點(diǎn)的關(guān)聯(lián)。

當(dāng)找到組成表結(jié)構(gòu)的第一個(gè)結(jié)點(diǎn)時(shí)泄隔,就能按照順序找到屬于這個(gè)表的其它結(jié)點(diǎn)。

單鏈表

單鏈表

如上圖(a)所示宛徊,單鏈表的結(jié)點(diǎn)是一個(gè)二元組佛嬉,elem保存元素的數(shù)據(jù),next表示下一個(gè)結(jié)點(diǎn)的標(biāo)識(shí)闸天。

為了掌握一個(gè)單鏈表暖呕,需要用一個(gè)變量來(lái)保存這個(gè)表的首結(jié)點(diǎn)的引用(或標(biāo)識(shí)),該變量可以稱之為表頭變量表頭指針

基本鏈表操作

  • 創(chuàng)建空鏈表
  • 刪除鏈表
  • 判斷鏈表是否為空
  • 加入元素
    • 首端加入
    • 尾端加入
    • 中間加入
  • 刪除元素
    • 首端刪除
    • 尾端刪除
    • 中間刪除
  • 遍歷鏈表
  • 查找元素

代碼實(shí)現(xiàn)苞氮,里面實(shí)現(xiàn)幾個(gè)典型方法

class Node:
    """結(jié)點(diǎn)"""
    def __init__(self, elem):
        self.elem = elem
        self.next = None

class SingleLinkList:
    """單鏈表"""
    def __init__(self):
        self._head = None

    def is_empty(self):
        """鏈表是否為空"""
        return self._head == None

    def length(self):
        """鏈表長(zhǎng)度"""
        # cur游標(biāo)湾揽,用來(lái)移動(dòng)遍歷結(jié)點(diǎn)
        cur = self._head
        # count記錄數(shù)量
        count = 0
        while cur != None:
            count += 1
            cur = cur.next
        return count

    def travel(self):
        """遍歷整個(gè)鏈表"""
        cur = self._head
        while cur != None:
            print(cur.elem, end=" ")
            cur = cur.next
        print("")

    def add(self, item):
        """鏈表頭部添加元素,頭插法"""
        node = Node(item)
        node.next = self._head
        self._head = node

    def append(self, item):
        """鏈表尾部添加元素, 尾插法"""
        node = Node(item)
        if self.is_empty():
            self._head = node
        else:
            cur = self._head
            while cur.next != None:
                cur = cur.next
            cur.next = node

    def insert(self, pos, item):
        """指定位置添加元素
        :param  pos 從0開(kāi)始
        """
        if pos <= 0:
            self.add(item)
        elif pos > (self.length()-1):
            self.append(item)
        else:
            pre = self._head
            count = 0
            while count < (pos-1):
                count += 1
                pre = pre.next
            # 當(dāng)循環(huán)退出后笼吟,pre指向pos-1位置
            node = Node(item)
            node.next = pre.next
            pre.next = node

    def remove(self, item):
        """刪除結(jié)點(diǎn)"""
        cur = self._head
        pre = None
        while cur != None:
            if cur.elem == item:
                # 先判斷此結(jié)點(diǎn)是否是頭結(jié)點(diǎn)
                # 頭結(jié)點(diǎn)
                if cur == self._head:
                    self._head = cur.next
                else:
                    pre.next = cur.next
                break
            else:
                pre = cur
                cur = cur.next

    def search(self, item):
        """查找結(jié)點(diǎn)是否存在"""
        cur = self._head
        while cur != None:
            if cur.elem == item:
                return True
            else:
                cur = cur.next
        return False

通過(guò)上面的代碼库物,可以說(shuō)明一下單鏈表的操作復(fù)雜度:

  • 創(chuàng)建空鏈表:O(1)
  • 判斷鏈表是否為空:O(1)
  • 鏈表長(zhǎng)度:O(n)
  • 加入元素:
    • 首端加入:O(1)
    • 尾端加入:O(n)
    • 中間加入:O(n)
  • 刪除元素:
    • 首端刪除:O(1)
    • 尾端刪除:O(n)
    • 中間刪除:O(n)
  • 遍歷,查找:O(n)

上面的單鏈表實(shí)現(xiàn)有個(gè)缺點(diǎn)贷帮,在尾端操作元素的效率低戚揭,只能從表頭開(kāi)始遍歷到尾部。
在實(shí)際中撵枢,會(huì)添加一個(gè)尾部結(jié)點(diǎn)的引用民晒,這樣在尾部添加精居,刪除元素測(cè)復(fù)雜度就降為O(1)。

循環(huán)單鏈表

循環(huán)單鏈表

單鏈表的一種變形是循環(huán)單鏈表潜必,它的最后一個(gè)結(jié)點(diǎn)的next不指向None靴姿,而是指向首結(jié)點(diǎn)的位置,如上圖所示磁滚。

代碼實(shí)現(xiàn)佛吓,部分和單鏈表類似

class SingleCycleLinkList:
    """單向循環(huán)鏈表"""
    def __init__(self):
        self._head = None

    def add(self, item):
        """鏈表頭部添加元素,頭插法"""
        node = Node(item)
        if self.is_empty():
            self._head = node
            node.next = node
        else:
            cur = self._head
            while cur.next != self._head:
                cur = cur.next
            # 退出循環(huán)恨旱,cur指向尾結(jié)點(diǎn)
            node.next = self._head
            self._head = node
            # cur.next = node
            cur.next = self._head

    def append(self, item):
        """鏈表尾部添加元素, 尾插法"""
        node = Node(item)
        if self.is_empty():
            self._head = node
            node.next = node
        else:
            cur = self._head
            while cur.next != self._head:
                cur = cur.next
            # node.next = cur.next
            node.next = self._head
            cur.next = node

    def insert(self, pos, item):
        """指定位置添加元素
        :param  pos 從0開(kāi)始
        """
        if pos <= 0:
            self.add(item)
        elif pos > (self.length()-1):
            self.append(item)
        else:
            pre = self._head
            count = 0
            while count < (pos-1):
                count += 1
                pre = pre.next
            # 當(dāng)循環(huán)退出后辈毯,pre指向pos-1位置
            node = Node(item)
            node.next = pre.next
            pre.next = node

    def remove(self, item):
        """刪除結(jié)點(diǎn)"""
        if self.is_empty():
            return

        cur = self._head
        pre = None

        while cur.next != self._head:
            if cur.elem == item:
                # 先判斷此結(jié)點(diǎn)是否是頭結(jié)點(diǎn)
                if cur == self._head:
                    # 頭結(jié)點(diǎn)的情況
                    # 找尾結(jié)點(diǎn)
                    rear = self._head
                    while rear.next != self._head:
                        rear = rear.next
                    self._head = cur.next
                    rear.next = self._head
                else:
                    # 中間結(jié)點(diǎn)
                    pre.next = cur.next
                return
            else:
                pre = cur
                cur = cur.next
        # 退出循環(huán),cur指向尾結(jié)點(diǎn)
        if cur.elem == item:
            if cur == self._head:
                # 鏈表只有一個(gè)結(jié)點(diǎn)
                self._head = None
            else:
                # pre.next = cur.next
                pre.next = self._head

其它的方法和單鏈表一樣搜贤。

同樣的谆沃,可以添加一個(gè)尾部結(jié)點(diǎn)的引用,使得運(yùn)算量下降仪芒。

雙向鏈表

帶有尾結(jié)點(diǎn)引用的雙向鏈表

單鏈表只有一個(gè)方向的鏈接唁影,從一個(gè)方向進(jìn)行鏈表的遍歷。為了是從兩端的插入和刪除操作都能高效完成掂名,可以加入另一個(gè)方向的鏈接据沈。如上圖所示,就形成了雙向鏈表饺蔑,或雙鏈表

雙向鏈表的結(jié)點(diǎn)除了next引用锌介,還需要一個(gè)prev引用:

class Node(object):
    """結(jié)點(diǎn)"""
    def __init__(self, item):
        self.elem = item
        self.next = None
        self.prev = None

雙向鏈表的一些操作要做一些修改:

class DoubleLinkList(object):
    """雙鏈表"""
    def __init__(self):
        self._head = None
        self._rear = None

    def add(self, item):
        """鏈表頭部添加元素,頭插法"""
        node = Node(item)
        if self.is_empty():
            self._rear = node

        node.next = self._head
        self._head = node
        node.next.prev = node

    def append(self, item):
        """鏈表尾部添加元素, 尾插法"""
        node = Node(item)
        if self.is_empty():
            self._head = node
        else:
            cur = self._head
            while cur.next != None:
                cur = cur.next
            cur.next = node
            node.prev = cur
        self._rear = node

    def insert(self, pos, item):
        """指定位置添加元素
        :param  pos 從0開(kāi)始
        """
        if pos <= 0:
            self.add(item)
        elif pos > (self.length()-1):
            self.append(item)
        else:
            cur = self._head
            count = 0
            while count < pos:
                count += 1
                cur = cur.next
            # 當(dāng)循環(huán)退出后猾警,cur指向pos位置
            node = Node(item)
            node.next = cur
            node.prev = cur.prev
            cur.prev.next = node
            cur.prev = node

    def remove(self, item):
        """刪除節(jié)點(diǎn)"""
        cur = self._head
        while cur != None:
            if cur.elem == item:
                # 先判斷此結(jié)點(diǎn)是否是頭節(jié)點(diǎn)
                # 頭節(jié)點(diǎn)
                if cur == self._head:
                    self._head = cur.next
                    if cur.next:
                        # 判斷鏈表是否只有一個(gè)結(jié)點(diǎn)
                        cur.next.prev = None
                    else:
                        self._rear = None
                else:
                    cur.prev.next = cur.next
                    if cur.next:
                        cur.next.prev = cur.prev
                    else:
                        self._rear = cur.prev
                break
            else:
                cur = cur.next

總結(jié)

鏈接表的優(yōu)點(diǎn):

  • 由于表結(jié)構(gòu)是由鏈接起來(lái)的結(jié)點(diǎn)形成孔祸,表結(jié)構(gòu)很容易修改;
  • 整個(gè)表由一些小的存儲(chǔ)塊構(gòu)成发皿,比較容易安排和管理崔慧,不需要連續(xù)的內(nèi)存塊。

缺點(diǎn):

  • 鏈表元素的定位需要線性的時(shí)間穴墅,比列表效率底惶室;
  • 鏈表的存儲(chǔ)代價(jià)會(huì)比列表高。

轉(zhuǎn)載自:
https://codeeper.com/2020/03/30/tech/python/structure/link-intro.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末玄货,一起剝皮案震驚了整個(gè)濱河市皇钞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌誉结,老刑警劉巖鹅士,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異惩坑,居然都是意外死亡掉盅,警方通過(guò)查閱死者的電腦和手機(jī)也拜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)趾痘,“玉大人慢哈,你說(shuō)我怎么就攤上這事∮榔保” “怎么了卵贱?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)侣集。 經(jīng)常有香客問(wèn)我键俱,道長(zhǎng),這世上最難降的妖魔是什么世分? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任编振,我火速辦了婚禮,結(jié)果婚禮上臭埋,老公的妹妹穿的比我還像新娘踪央。我一直安慰自己,他們只是感情好瓢阴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布畅蹂。 她就那樣靜靜地躺著,像睡著了一般荣恐。 火紅的嫁衣襯著肌膚如雪液斜。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,521評(píng)論 1 304
  • 那天叠穆,我揣著相機(jī)與錄音旗唁,去河邊找鬼。 笑死痹束,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的讶请。 我是一名探鬼主播祷嘶,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼夺溢!你這毒婦竟也來(lái)了论巍?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤风响,失蹤者是張志新(化名)和其女友劉穎嘉汰,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體状勤,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鞋怀,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年双泪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片密似。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡焙矛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出残腌,到底是詐尸還是另有隱情村斟,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布抛猫,位于F島的核電站蟆盹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏闺金。R本人自食惡果不足惜逾滥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望掖看。 院中可真熱鬧匣距,春花似錦、人聲如沸哎壳。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)归榕。三九已至尸红,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間刹泄,已是汗流浹背外里。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留特石,地道東北人盅蝗。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像姆蘸,于是被迫代替她去往敵國(guó)和親墩莫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

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