Python實現單向鏈表的封裝

首先我們先了解順序表和鏈表的概念,爲什麼要使用鏈表。

順序表和鏈表

順序表

順序表的構建需要預先知道數據大小來申請連續的存儲空間,而在進行擴充時需要進行數據搬遷,所以使用起來不是很靈活。
在這裏插入圖片描述
鏈表

鏈表(Linked List) 是一種常見的基礎數據結構,是一隻種類線性表,但是不像順序表一樣連續存儲數據,而是在每一個節點(數據存儲單元)裏存放下一個節點的位置信息(即地址)。

鏈表結構可以充分利用計算機內存空間,實現靈活的內存動態管理。

在這裏插入圖片描述
順序表和鏈表的內存分佈
在這裏插入圖片描述

單向鏈表

單向鏈表也叫單鏈表,每個節點包含兩個域,一個信息域(元素域)和一個鏈接域。這個鏈接指向鏈表中的下一個節點,而最後一個節點的鏈接域則指向一個空值。
在這裏插入圖片描述
表元素域elem 用來存放具體的數據。
鏈接域next 用來存放下一個節點的位置(python中的標識)
• 變量p指向鏈表的頭節點(首節點)的位置,從p出發能找到表中的任意節點。

單鏈表的操作

在這裏插入圖片描述
鏈表實現之前,需要先實現節點,代碼如下:

class Node(object):
    """單鏈表節點的封裝"""
    def __init__(self, element):
        self.element = element
        self.next = None

我們先實現判斷鏈表是否爲空,鏈表長度和遍歷鏈表的操作代碼:

class Node(object):
    """單鏈表節點的封裝"""
    def __init__(self, element):
        self.element = element
        self.next = None

class SingleLink(object):
    """單鏈表的封裝"""
    def __init__(self):
        # 默認爲空
        self._head = None

    def is_empty(self):
        """是否爲空"""
        return self._head == None

    def __len__(self):
        """
        求鏈表長度
            1. 判斷是否爲空,爲空直接返回0
            2. 不爲空時依次遍歷,長度加1之後將下一個節點賦值給當前
        """
        if self.is_empty():
            return 0
        else:
            cur = self._head
            length = 0
            while cur != None:
                length += 1
                cur = cur.next
            return length

    def travel(self):
        """遍歷鏈表"""
        if self.is_empty():
            print('空鏈表')
        else:
            cur = self._head
            while cur.next != None:
                print(cur.element, end=',')
                cur = cur.next
            print(cur.element)

單鏈表的頭部添加元素

在這裏插入圖片描述

class SingleLink(object):
    """單鏈表的封裝"""
    def __init__(self):
        # 默認爲空
        self._head = None
        
    def add(self, item):
        """
        頭部添加元素:
            1. 創建一個保存item值的節點
            2. 將新節點的next指向頭結點,即_head指向的位置
            3. 將鏈表的頭_head指向新節點
        :param item:
        :return:
        """
        node = Node(item)
        node.next = self._head
        self._head = node

指定位置添加元素
在這裏插入圖片描述

class SingleLink(object):
    """單鏈表的封裝"""
    def __init__(self):
        # 默認爲空
        self._head = None
        
    def insert(self, index, item):
        """
        指定位置添加元素
            1. 指定位置爲頭部之前,則頭部添加元素
            2. 指定位置爲尾部之後,則尾部添加元素
            3. 中間位置:需要找出指定位置的前一個元素,得到其尾部,插入的節點的尾部指向前面得到的尾部,
                        前一個元素新的尾部指向插入的頭部
        :param index:
        :param item:
        :return:
        """

        if index <= 0:
            self.add(item)
        elif index >= len(self):
            self.append(item)
        else:
            node = Node(item)
            count = 0  # 當前節點的位置
            cur = self._head
            # 尋找插入節點的前一個節點
            while count < index - 1:
                count += 1
                cur = cur.next
            # 插入節點的前一個節點的尾部成爲了插入節點的尾部指向
            # 然後將插入節點的前一個節點的尾部指向更新爲新插入節點的頭部
            node.next = cur.next
            cur.next = node

刪除節點
在這裏插入圖片描述

    def remove(self, item):
        """
        刪除指定元素的節點
            1. 刪除頭部節點
            2. 刪除其他位置的節點
        :param item:
        :return:
        """
        """
            既然要刪除當前節點,首先想的就是遍歷鏈表找到對應節點並且刪除,
            這裏直接省去了遍歷的操作,直接給出了對應的節點。 
            既然想刪除當前節點那麼將給定的節點的val和next全部轉換成當前節點的下一個節點所對應的值,
            那麼當前節點在本鏈表中就相當於替換成了下一個節點。
            """
        cur = self._head
        pre = None
        while cur != None:
            if cur.element == item:
                if not pre:
                    self._head = cur.next
                else:
                    pre.next = cur.next
                break
            else:
                pre = cur
                cur = cur.next

尾部添加元素

    def append(self, item):
        """
        尾部添加元素
            1. 先判斷鏈表是否爲空,若爲空,將_head指向新節點
            2. 若不爲空,找到尾部,將尾節點next指向新節點
        :param item:
        :return:
        """
        node = Node(item)
        if self.is_empty():
            self._head = node
        else:
            cur = self._head
            while cur.next != None:
                cur = cur.next
            if cur.next == None:
                cur.next = node

判斷元素在鏈表中是否存在

    def search(self, item):
        """
        判斷查找的元素在節點中是否存在,返回Bool類型
        :param item:
        :return:
        """
        cur = self._head
        while cur.next != None:
            if cur.element == item:
                return True
            cur = cur.next
        if cur.element == item:
            return True

        return False

鏈表與順序表的對比

操作 鏈表 順序表
訪問元素 O(n) O(1)
在頭部插入/刪除 O(1) O(n)
在尾部插入/刪除 O(n) O(1)
在中間插入/刪除 O(n) O(n)

時間複雜度的不同主要是因爲鏈表和順序表在插入和刪除時進行的是完全不同的操作。鏈表的主要耗時操作是遍歷查找。順序表查找很快,主要耗時的操作是拷貝覆蓋。因爲除了目標元素在尾部的特殊情況,順序表進行插入和刪除時需要對操作點之後的所有元素進行前後移位操作,只能通過拷貝和覆蓋的方法進行。

python實現單向鏈表的整體代碼

class Node(object):
    """單鏈表節點的封裝"""
    def __init__(self, element):
        self.element = element
        self.next = None

class SingleLink(object):
    """單鏈表的封裝"""
    def __init__(self):
        # 默認爲空
        self._head = None

    def is_empty(self):
        """是否爲空"""
        return self._head == None

    def __len__(self):
        """
        求鏈表長度
            1. 判斷是否爲空,爲空直接返回0
            2. 不爲空時依次遍歷,長度加1之後將下一個節點賦值給當前
        """
        if self.is_empty():
            return 0
        else:
            cur = self._head
            length = 0
            while cur != None:
                length += 1
                cur = cur.next
            return length

    def travel(self):
        """遍歷鏈表"""
        if self.is_empty():
            print('空鏈表')
        else:
            cur = self._head
            while cur.next != None:
                print(cur.element, end=',')
                cur = cur.next
            print(cur.element)

    def append(self, item):
        """
        尾部添加元素
            1. 先判斷鏈表是否爲空,若爲空,將_head指向新節點
            2. 若不爲空,找到尾部,將尾節點next指向新節點
        :param item:
        :return:
        """
        node = Node(item)
        if self.is_empty():
            self._head = node
        else:
            cur = self._head
            while cur.next != None:
                cur = cur.next
            if cur.next == None:
                cur.next = node


    def add(self, item):
        """
        頭部添加元素:
            1. 創建一個保存item值的節點
            2. 將新節點的next指向頭結點,即_head指向的位置
            3. 將鏈表的頭_head指向新節點
        :param item:
        :return:
        """
        node = Node(item)
        node.next = self._head
        self._head = node

    def insert(self, index, item):
        """
        指定位置添加元素
            1. 指定位置爲頭部之前,則頭部添加元素
            2. 指定位置爲尾部之後,則尾部添加元素
            3. 中間位置:需要找出指定位置的前一個元素,得到其尾部,插入的節點的尾部指向前面得到的尾部,
                        前一個元素新的尾部指向插入的頭部
        :param index:
        :param item:
        :return:
        """

        if index <= 0:
            self.add(item)
        elif index >= len(self):
            self.append(item)
        else:
            node = Node(item)
            count = 0  # 當前節點的位置
            cur = self._head
            # 尋找插入節點的前一個節點
            while count < index - 1:
                count += 1
                cur = cur.next
            # 插入節點的前一個節點的尾部成爲了插入節點的尾部指向
            # 然後將插入節點的前一個節點的尾部指向更新爲新插入節點的頭部
            node.next = cur.next
            cur.next = node

    def remove(self, item):
        """
        刪除指定元素的節點
            1. 刪除頭部節點
            2. 刪除其他位置的節點
        :param item:
        :return:
        """
        """
            既然要刪除當前節點,首先想的就是遍歷鏈表找到對應節點並且刪除,
            這裏直接省去了遍歷的操作,直接給出了對應的節點。 
            既然想刪除當前節點那麼將給定的節點的val和next全部轉換成當前節點的下一個節點所對應的值,
            那麼當前節點在本鏈表中就相當於替換成了下一個節點。
            """
        cur = self._head
        pre = None
        while cur != None:
            if cur.element == item:
                if not pre:
                    self._head = cur.next
                else:
                    pre.next = cur.next
                break
            else:
                pre = cur
                cur = cur.next



    def search(self, item):
        """
        判斷查找的元素在節點中是否存在,返回Bool類型
        :param item:
        :return:
        """
        cur = self._head
        while cur.next != None:
            if cur.element == item:
                return True
            cur = cur.next
        if cur.element == item:
            return True

        return False

if __name__ == '__main__':
    # 實例化單鏈表對象
    link = SingleLink()
    # 長度獲取
    # print("鏈表長度:", len(link))
    # # 遍歷鏈表
    # link.travel()
    # print("鏈表是否爲空?", link.is_empty())
    link.add(3)
    print(link.travel())
    link.append(1)
    link.append(2)
    print(link.travel())
    print("鏈表是否爲空?", link.is_empty())
    link.insert(1, 'hello')
    print(link.travel())
    print("鏈表長度:", len(link))
    link.remove(3)
    print(link.travel())
    print(link.search(2))

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章