鏈表(三)

單向鏈表

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

class SingleLinkList(object):
    '''單鏈表'''
    def __init__(self,node=None):
        #內(nèi)部私有函數(shù),鏈表頭的初始化,可以直接建立空鏈表
        self.__head = node

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

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

    def travel(self):
        """遍歷鏈表"""
        cur = self.__head
        while cur != None:
            print(cur.elem,end=' ')
            cur = cur.next

    def add(self, item):
        """頭部添加節(jié)點(diǎn)"""
        node = Node(item)
        node.next = self.__head
        self.__head = node

    def append(self, item):
        """尾部添加節(jié)點(diǎn)"""
        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):
        """在指定位置添加節(jié)點(diǎn)"""
        pre = self.__head
        count = 0
        if pos <= 0:
            self.add(item)
        elif pos >= (self.length()-1):
            self.append(item)
        else:
            while count < (pos-1):
                count += 1
                pre = pre.next
            node = Node(item)
            node.next = pre.next
            pre.next = node

    def remove(self, item):
        """刪除一個(gè)節(jié)點(diǎn)"""
        cur = self.__head
        pre = None
        while cur != None:
            if cur.elem == item:
                #先判斷是否為頭節(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

根據(jù)這段代碼,結(jié)合下圖,是不是進(jìn)一步加深了我們對(duì)時(shí)間復(fù)雜度的理解。
  • 鏈表失去了順序表隨機(jī)讀取的優(yōu)點(diǎn),同時(shí)鏈表由于增加了結(jié)點(diǎn)的指針域,空間開(kāi)銷(xiāo)比較大,但對(duì)存儲(chǔ)空間的使用要相對(duì)靈活。
  • 注意雖然表面看起來(lái)復(fù)雜度都是 O(n),但是鏈表和順序表在插入和刪除時(shí)進(jìn)行的是完全不同的操作。鏈表的主要耗時(shí)操作是遍歷查找,刪除和插入操作本身的復(fù)雜度是O(1)。順序表查找很快,主要耗時(shí)的操作是拷貝覆蓋。因?yàn)槌四繕?biāo)元素在尾部的特殊情況,順序表進(jìn)行插入和刪除時(shí)需要對(duì)操作點(diǎn)之后的所有元素進(jìn)行前后移位操作,只能通過(guò)拷貝和覆蓋的方法進(jìn)行。

雙向鏈表

100節(jié)點(diǎn)是40節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn),6節(jié)點(diǎn)是40節(jié)點(diǎn)的后繼節(jié)點(diǎn)。
一種更復(fù)雜的鏈表是“雙向鏈表”或“雙面鏈表”。每個(gè)節(jié)點(diǎn)有兩個(gè)鏈接:一個(gè)指向前一個(gè)節(jié)點(diǎn),當(dāng)此節(jié)點(diǎn)為第一個(gè)節(jié)點(diǎn)時(shí),指向空值;而另一個(gè)指向下一個(gè)節(jié)點(diǎn),當(dāng)此節(jié)點(diǎn)為最后一個(gè)節(jié)點(diǎn)時(shí),指向空值。

代碼實(shí)現(xiàn),我們就在單向鏈表的基礎(chǔ)上更改

  • 我們先看看雙鏈表的構(gòu)造

    是不是和單鏈表如出一轍,無(wú)需更改程序。

  • 我們看看雙鏈表的探空功能:

    這樣是不是又和單鏈表一樣了。

  • 我們看看求長(zhǎng)度的功能:
    我們只需要計(jì)數(shù),是不是完全可以把它當(dāng)成單鏈表,只需要一個(gè)游標(biāo)next就可以實(shí)現(xiàn)求長(zhǎng)度啊,遍歷的travel和求長(zhǎng)度一樣都可以看作是單鏈表,簡(jiǎn)單粗暴。
  • 我們看看從頭部添加的功能:

    我們是不是要先操作新節(jié)點(diǎn)啊
    這樣就可以實(shí)現(xiàn)。
    但如果用代碼實(shí)現(xiàn)的話(huà),可以有兩種方式,與指向的前后順序相關(guān):

    1 方法一

 def add(self, item):
        """頭部添加節(jié)點(diǎn)"""
        node = Node(item)
        node.next = self.__head
        self.__head = node
        node.next.prev = node

2 方法二

    def add(self, item):
        """頭部添加節(jié)點(diǎn)"""
        node = Node(item)
        node.next = self.__head
        self.__head.prev = node
        self.__head = node
  • 實(shí)現(xiàn)鏈表尾部添加元素的功能:

    尾插法是不是首先要定位啊,定位到最后一個(gè)元素,這個(gè)過(guò)程雙鏈表和單鏈表是沒(méi)有區(qū)別的,定位到最后一個(gè)元素后
    只要實(shí)現(xiàn)這樣的指向就OK了吧,那要怎么實(shí)現(xiàn)呢。
    def append(self, item):
        """尾部添加節(jié)點(diǎn)"""
        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

考慮一下特殊情況,加入這個(gè)鏈表為空鏈表呢,程序也是沒(méi)問(wèn)題的。

  • 實(shí)現(xiàn)insert插入功能:

    我們先截個(gè)單鏈表中的insert代碼
    我們看看雙鏈表中需要怎么更改呢?

    這一部分是不需要更改的吧,位置小于等于0我們就調(diào)用頭插法,pos大于等于(length() - 1,我們就調(diào)用尾插法。唯一需要更改的就是,最后的指向問(wèn)題。
    這么一來(lái)是不是就一目了然
  • 先操作node節(jié)點(diǎn),讓node節(jié)點(diǎn)分別指向節(jié)點(diǎn)6和節(jié)點(diǎn)40,node.next = cur,node.prev = cur.prev
  • 然后讓節(jié)點(diǎn)40和節(jié)點(diǎn)6分別對(duì)接node節(jié)點(diǎn),cur.prev.next = node,cur.prev = node


    這么寫(xiě)也可以。
    那么完整的代碼怎么實(shí)現(xiàn)呢,顯然需要做一些更改,首先pre這個(gè)游標(biāo)就不需要了,我們只需要一個(gè)cur游標(biāo),且count < pos即可。

    def insert(self, pos, item):
        """在指定位置添加節(jié)點(diǎn)"""
        cur = self.__head
        count = 0
        if pos <= 0:
            self.add(item)
        elif pos >= (self.length() - 1):
            self.append(item)
        else:
            while count < pos:
                count += 1
                cur = cur.next
            node = Node(item)
            node.next = cur
            node.prev = cur.prev
            cur.prev.next = node
            cur.prev = node
測(cè)試結(jié)果沒(méi)問(wèn)題
  • 實(shí)現(xiàn)刪除的功能:

    那如果要?jiǎng)h除的是頭節(jié)點(diǎn)要怎么處理呢?
    這樣是不是OK
    那如果原有的鏈表只有一個(gè)節(jié)點(diǎn)要如何處理呢?我們還是直接看代碼吧。
 def remove(self, item):
        """刪除一個(gè)節(jié)點(diǎn)"""
        cur = self.__head
        while cur != None:
            if cur.elem == item:
                # 先判斷是否為頭節(jié)點(diǎn),然后再去處理頭節(jié)點(diǎn)
                if cur == self.__head:
                    self.__head = cur.next
                    if cur.next:
                        cur.next.prev = None
                else:
                    cur.prev.next = cur.next
                    if cur.next:
                       cur.next.prev = cur.prev
                break
            else:
                cur = cur.next
測(cè)試結(jié)果一切正常
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容