大話數據結構 - 鏈表

1. 順序表的缺陷
線性表的順序存儲結構有致命的缺陷, 由於地址的連續性, 插入和刪除都需要移動大量的元素。其次是在C、C++等語言中,數組的長度有限,這可能帶來極大的不便。

2. 鏈表 - 線性表的鏈式存儲結構
鏈表爲了擺脫順序表的缺陷, 從物理結構上鍊表各個元素是隨機位置, 而不是連續存儲; 這樣也就導致了每個節點除了存儲本身的數據之外還需要存儲下一個節點的地址;

這是的插入和刪除非常方便, 但是無法像順序表那樣直接獲取某個位置的元素, 只能從頭結點往下遍歷。


3. 單鏈表的Python實現

# -*- coding: utf-8 -*-

class Node:
    def __init__(self, data):
        # 鏈表節點類, 數據域及指針域
        self.data = data
        self.next = None
        
class Linklist:
    """
    線性表的鏈式存儲結構: 鏈表
    
    屬性:
        頭結點, 鏈表長度
    
    方法:
        1. 獲取鏈表中第i個位置的元素
        2. 向鏈表任意位置插入元素
        3. 刪除鏈表任意位置的一個元素
        
    幾乎所有的鏈表操作, 都是先要引用鏈表的頭結點
    
    """
    def __init__(self, node):
        # 頭結點, 鏈表長度
        self.head = node
        self.length = 1
        
    def _get_list_length(self):
        # 獲取鏈表的長度
        current = self.head
        length = 0
        while current != None:
            current = current.next
            length += 1
        return length
    
    def get_i_ele(self, i):
        # 1. 獲取鏈表中第i個位置的元素
        if i not in range(0, self.length): raise(Exception("輸入參數錯誤"))
        
        current = self.head; k = 0
        while i != k: 
            current = current.next
            k += 1
        return current.data
        
    def insert(self, i, data):
        # 2. 向鏈表任意位置插入元素
        if i not in range(0, self.length+1): raise(Exception("輸入參數錯誤"))
        current = self.head
        if i != 0:
            k = 0
            while k < i: 
                if k == i - 1: previous_node = current # 待插入節點的上一個節點
                current = current.next
                k += 1
            inserted_node = Node(data) # 新建一個待插入的節點
            previous_node.next = inserted_node # 把上一個節點指向待插入節點
            inserted_node.next = current # 待插入的節點指向下一個節點
       
        # 插入的位置是頭結點
        else:
            inserted_node = Node(data)  # 新建一個待插入的節點
            self.head = inserted_node # 把頭結點變成待插入的節點
            self.head.next = current
            
        # 更新鏈表的長度
        self.length += 1
        
    def delete(self, i):
        # 3. 刪除鏈表中第i個位置的元素
        if i not in range(0, self.length+1): raise(Exception("輸入參數錯誤"))
        current = self.head
        length = self.length
        for j in range(length):
            if j == i-1:
                previous_node = current
                break
            current = current.next
        current = current.next.next
        previous_node.next = current
        self.length -= 1
        
    def clear_list(self):
        # 清空整個鏈表
        self.head = None
        self.length = 0
        
    def print_List(self):
        # 打印整個鏈表
        current = self.head
        k = 0
        print("\n")
        while current != None:
            print("鏈表中的第{0}個元素 = {1}".format(k, current.data))
            current = current.next
            k += 1
            
def test():
    # 創建頭結點
    node = Node(0)
    
    # 創建鏈表
    List = Linklist(node)
    
    print("\n鏈表的長度 = {0}".format(List.length))
    
    # 向鏈表中插入節點
    for i in range(1,10):
        List.insert(i, i)
    List.insert(0, 100)
    
    # 打印當前鏈表
    List.print_List()
    
    # 刪除節點
    List.delete(7)
    
    # 打印當前鏈表
    List.print_List()
    
    # 清空整個鏈表
    List.clear_list()
    
    # 打印當前鏈表
    List.print_List()    

4. 單鏈表與順序表

1)若需要頻繁讀取時,應採用順序表,比如網站的用戶註冊信息,一般較少修改,讀取較多,宜採用順序表;而遊戲中玩家的裝備,道具等等經常發生增加和刪除等操作,此時更易使用鏈表。

2)當線性表中的元素個數變化變化太大,或者個數難以估計時,宜採用鏈表


5. 循環鏈表與雙向鏈表

循環鏈表:單鏈表的操作核心就是抓住表頭,但是通常一個鏈表除了表頭,表尾也是我們經常需要的。循環鏈表就是讓表尾的指針不再指到null而是指到表頭。因此這兒也是循環鏈表和單鏈表操作上的最大區別:單鏈表是判斷p->next是否爲空來判斷程序是否終止;而循環鏈表是判斷p->next是否等於頭結點來判斷程序是否終止。

雙向鏈表:單鏈表的節點類包括一個指針和數據,其中指針的不斷傳遞和連接構成了鏈表的方向性。那麼顯然雙向鏈表就是每個節點有兩個指針,分別指向上一個節點和下一個節點。這樣一來雖然使用更方便,但是結構就變得更復雜,比如在刪除和插入節點時需要同時更改上游節點和下游節點四個指針的指向。


發佈了139 篇原創文章 · 獲贊 141 · 訪問量 45萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章