1. 程式人生 > >python資料結構之連結串列(linked list)

python資料結構之連結串列(linked list)

目錄

  1. 基礎 知識
    1.1 連結串列的基本結構
    1.2 節點類和連結串列節點的定義
    1.3 順序列印和逆序列印
  2. 連結串列的基本操作
    2.1 計算連結串列長度
    2.2 從前,後插入資料
    2.3 查詢與刪除

參考

1.基礎 知識

1.1 連結串列的基本結構

連結串列是通過一個個節點組成的,每個節點都包含了稱為cargo的基本單元,它也是一種遞迴的資料結構。它能保持資料之間的邏輯順序,但儲存空間不必按照順序儲存。
如圖:
這裡寫圖片描述
連結串列的基本元素有:

  • 節點:每個節點有兩個部分,左邊部分稱為值域,用來存放使用者資料;右邊部分稱為指標域,用來存放指向下一個元素的指標。
  • head:head節點永遠指向第一個節點
  • tail: tail永遠指向最後一個節點
  • None:連結串列中最後一個節點的指標域為None值

但連結串列也分為單向連結串列和單向迴圈連結串列,雙向連結串列和雙向迴圈連結串列,如圖為單向連結串列和單向迴圈連結串列:
這裡寫圖片描述

寫個基本程式測試一下:

1.2 節點類和連結串列節點的定義

節點類定義如下:

class Node:
    def __init__(self,cargo = None, next = None):
        self.cargo = cargo
        self.next = next
    def
__str__(self):
#測試基本功能,輸出字串 return str(self.cargo) print Node("text") #輸出text

因為任何值都能通過str函式,且能儲存下來。

連結串列怎麼定義呢?
我們可以先定義一個一個節點,如下:

node1 = Node(1)
node2 = Node(2)
node3 = Node(3)

然後再把每個節點的關係表示出來,就OK了

node1.next = node2
node2.next = node3

1.3 順序列印和逆序列印

因為先前已經建立了關係,所以可以通過輸入第一個節點,迴圈整個連結串列然後順序列印整個連結串列。

def printList(node):
    while node:
        print node
        node = node.next
printList(node1)
1
2
3

使用遞迴的方法來列印,主要步驟如下:

  1. 將list拆分成兩個部分,head:第一個元素,tail:其餘元素
  2. 向後列印
  3. 列印第一個元素
def printBackward(lists):
    if lists == None:
        return
    head = lists
    tail= lists.next
    print head,tail
    printBackward(tail)
    print head,tail
printBackward(node1)
1 2
2 3
3 None
3 None
2 3
1 2

事實上,還能更簡便。

def printBackward(lists):
    if lists == None:return
    printBackward(lists.next)
    print lists
printBackward(node1)

2.連結串列的基本操作

在連結串列的基本操作中,包括插入,刪除等,但要注意的是一下的操作是針對非迴圈連結串列的,從頭節點開始操作,而且我們不能插入 None值到連結串列中。

2.1 計算連結串列長度

class Node(object):
#節點類
    #功能:輸入一個值data,將值變為一個節點
    def __init__(self, data, next = None):
        self.data = data
        self.next = next

    def __str__(self):
        return self.data

class LinkedList(object):

    def __init__(self, head = None):
        self.head = head
    def __len__(self):
        #功能:輸入頭節點,返回連結串列長度
        curr = self.head
        counter = 0
        while curr is not None:
            counter += 1
            curr = curr.next
        return counter

2.2 從前,後插入

從前插入:

  • 被插入資料為空,返回
  • 使用該輸入資料建立一個節點,並將該節點指向原來頭節點
  • 設定該節點為頭節點

時間複雜度和空間複雜度均為O(1)

    def insertToFront(self,data):
        #功能:輸入data,插入到頭節點前,並更改為頭節點
        #輸出:當前頭節點
        if data is None:
            return None
        node = Node(data,self.head)
        self.head = node
        return node

從後:append

  • 若輸入資料為空,返回None
  • 若頭節點為空,直接將輸入資料作為頭節點
  • 遍歷整個連結串列,直到當前節點的下一個節點為None時,將當前節點的下一個節點設定為輸入資料

時間複雜度為O(n),空間O(1)

    def append(self,data):
        #功能:輸入data,作為節點插入到末尾
        if data is None:
            return None
        node = Node(data)
        if self.head is None:
            self.head = node
            return node
        curr_node = self.head
        while curr_node.next is not None:
            curr_node = curr_node.next
        curr_node.next = node
        return node

2.3 查詢與刪除

查詢

  • 若查詢的資料為空,返回
  • 設定頭節點為當前節點,若當前節點不為None,遍歷整個連結串列
  • 若當前節點的data與輸入的data相同,但會當前節點,否則輪到下一個節點

可見時間複雜度為O(n),空間複雜度為O(1).

    def find(self,data):
        #功能:查詢連結串列的節點data與data相同的節點
        if data is None:
            return None
        curr_node = self.head
        while curr_node is not None:
            if curr_node.data == data:
                return curr_node
            curr_node = curr_node.next
        return None

刪除1
申請兩個變數,如果遇到匹配的,不用刪除,直接將匹配節點的前一節點指向匹配節點的下一節點,因此需要定義一個前節點和一個當前節點,當前節點用來判斷是否與輸入資料匹配,前節點用來更改連結串列的指向。

  • 若輸入資料為None,返回
  • 將頭節點設定為前節點,頭節點的下一個節點設定為當前節點
  • 判斷前節點是否與輸入資料匹配,若匹配,將頭節點設定為當前節點
  • 遍歷整個連結串列,若當前節點與輸入資料匹配,將前節點的指標指向當前節點的下一個節點,否則,移到下一個節點

時間複雜度為O(n),空間複雜度為O(1).

   def delete(slef,data):
        #刪除節點
        if data is None:
            return None
        if self.head is None:
            return None
        if self.head.data == data:
            self.head = self.head.next
            return
        prev_node = self.head
        curr_node = self.head.next
        while curr_node is not None:
            if curr_node.data == data:
                prev_node.next = curr_node.next
            else:
                prev_node = curr_node
                curr_node = curr_node.next

刪除2
第二種解決辦法就是隻定義一個變數作為當前節點,使用它的下一個節點去判斷是否與資料資料匹配,若匹配,直接將當前節點指向下下一個節點。

時間複雜度為O(n),空間複雜度為O(1).

    def deleteAlt(self):
        #只定義一個變數來完成刪除操作
        if data is None:
            return 
        if self.head is None:
            return 
        if self.head.data == data:
            self.head = self.head.next
            return
        curr_node = self.head
        while curr_node.next is not None:
            if curr_node.next.data == data:
                curr_node.next = curr_node.next.next
                return
            curr_node = curr_node.next

reference