鏈表的實現 ------ Python數據結構與算法第4章

1. 鏈表概述

      爲什麼需要鏈表?順序表的構建需要預先知道數據大小來申請連續的存儲空間,而在進行擴充時又需要進行數據的搬遷,所以使用起來並不是很靈活。鏈表結構可以充分利用計算機內存空間,實現靈活的內存動態管理
      鏈表(Linked list)是一種常見的基礎數據結構,是一種線性表,但是不像順序表一樣連續存儲數據,而是在每一個節點(數據存儲單元)裏存放下一個節點的位置信息(即地址)。
在這裏插入圖片描述

2. 鏈表與順序表的對比

      鏈表失去了順序表隨機讀取的優點,同時鏈表由於增加了結點的指針域,空間開銷比較大,但對存儲空間的使用要相對靈活。鏈表與順序表的各種操作複雜度如下所示:
在這裏插入圖片描述
       雖然表面看起來複雜度都是 O(n),但是鏈表和順序表在插入和刪除時進行的是完全不同的操作。鏈表的主要耗時操作是遍歷查找,刪除和插入操作本身的複雜度是O(1)。順序表查找很快,主要耗時的操作是拷貝覆蓋。因爲除了目標元素在尾部的特殊情況,順序表進行插入和刪除時需要對操作點之後的所有元素進行前後移位操作,只能通過拷貝和覆蓋的方法進行。

3. 單向鏈表

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

單鏈表中節點的實現:

class SingleNode:
    def __init__(self, elem):
        # 存放數據元素
        self.item = elem
        # 下一個節點的標識
        self.next = None

       單鏈表的操作有判斷鏈表是否爲空、獲取鏈表的長度、遍歷整個鏈表、鏈表頭部添加元素、鏈表尾部添加元素、指定位置添加元素、刪除節點和查找節點,下面實現這些操作:

class SingleNode:
    def __init__(self, elem):
        self.elem = elem
        self.next = None


class SimpleLinkedList:
    """
    單向鏈表
    """

    def __init__(self, node=None):
        """
        :param node:默認是空鏈表
        """
        self.__head = node

    def is_empty(self):
        """
        判斷是否爲空
        :return:
        """
        return self.__head is None

    def length(self):
        """
        鏈表的長度
        :return:count
        """
        # 如果是空鏈表直接就返回count=0
        cur = self.__head
        count = 0
        while cur is not None:
            count += 1
            cur = cur.next
        return count

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

    def add(self, elem):
        """
        從鏈表的頭部添加元素
        :param elem:
        :return:
        """
        node = SingleNode(elem)
        """
        # 下面也可以處理是空鏈表的情況
        if self.is_empty():
            self.__head = node
        node.next = self.__head
        """
        node.next = self.__head
        self.__head = node

    def append(self, elem):
        """
        尾部添加元素
        :param elem:
        :return:
        """
        node = SingleNode(elem)
        if self.is_empty():
            self.__head = node
        else:
            cur = self.__head
            while cur.next is not None:
                cur = cur.next
            cur.next = node

    def insert(self, pos, elem):
        node = SingleNode(elem)
        if pos <= 0:
            self.add(elem)
            return
        elif pos > self.length() - 1:
            self.append(elem)
            return
        pre = self.__head
        count = 0
        while count < pos - 1:
            pre = pre.next
            count += 1
        node.next = pre.next
        pre.next = node

    def search(self, elem):
        """
        查找元素
        :param self:
        :param elem:
        :return:
        """
        # 也可以處理空鏈表的情況
        cur = self.__head
        while cur is not None:
            if cur.elem == elem:
                return True
            else:
                cur = cur.next
        return False

    def remove(self, elem):
        pre = None
        cur = self.__head
        # 適用於空節點和刪除頭節點
        while cur is not None:
            if cur.elem == elem:
                # 判斷當前節點是否是頭節點
                # 也可以解決鏈表中只有一個頭節點
                if cur == self.__head:
                    self.__head = self.__head.next
                    # self.__head = cur.next
                else:
                    # 也適用於刪除尾部節點
                    pre.next = cur.next
                break
            else:
                pre = cur
                cur = cur.next


sll = SimpleLinkedList()
print('當前鏈表是否爲空:', sll.is_empty())
print('當前鏈表長度:', sll.length())
print('------在鏈表尾部添加節點------')
sll.append(1)
print('當前鏈表是否爲空:', sll.is_empty())
print('當前鏈表長度:', sll.length())
sll.append(2)
sll.append(3)
sll.append(4)
sll.append(5)
sll.append(6)
print('當前鏈表是否爲空:', sll.is_empty())
print('當前鏈表長度:', sll.length())
print('遍歷鏈表:', end='')
sll.travel()
print('\n------在鏈表頭部添加節點-----')
sll.add(7)
print('當前鏈表是否爲空:', sll.is_empty())
print('當前鏈表長度:', sll.length())
print('遍歷鏈表:', end='')
sll.travel()
print('\n------在指定位置插入節點-----')
sll.insert(0, 8)
sll.insert(2, 9)
sll.insert(9, 10)
sll.insert(10, 10)
print('當前鏈表是否爲空:', sll.is_empty())
print('當前鏈表長度:', sll.length())
print('遍歷鏈表:', end='')
sll.travel()
print('\n------刪除指定位置的元素,實現的效果類似列表的remove方法-----')
sll.remove(7)
sll.remove(1)
sll.remove(10)
print('當前鏈表是否爲空:', sll.is_empty())
print('當前鏈表長度:', sll.length())
print('遍歷鏈表:', end='')
sll.travel()
"""
當前鏈表是否爲空: True
當前鏈表長度: 0
------在鏈表尾部添加節點------
當前鏈表是否爲空: False
當前鏈表長度: 1
當前鏈表是否爲空: False
當前鏈表長度: 6
遍歷鏈表:1 2 3 4 5 6 
------在鏈表頭部添加節點-----
當前鏈表是否爲空: False
當前鏈表長度: 7
遍歷鏈表:7 1 2 3 4 5 6 
------在指定位置插入節點-----
當前鏈表是否爲空: False
當前鏈表長度: 11
遍歷鏈表:8 7 9 1 2 3 4 5 6 10 10 
------刪除指定位置的元素,實現的效果類似列表的remove方法-----
當前鏈表是否爲空: False
當前鏈表長度: 8
遍歷鏈表:8 9 2 3 4 5 6 10
"""
4. 雙向鏈表

       一種更復雜的鏈表是“雙向鏈表”或“雙面鏈表”。每個節點有兩個鏈接:一個指向前一個節點,當此節點爲第一個節點時,指向空值。而另一個指向下一個節點,當此節點爲最後一個節點時,指向空值。雙向鏈表引入 前驅節點和後繼節點,實現的操作與單鏈表相同,只是需要考慮節點。

節點的實現:

class DoubleNnode:
    def __init__(self, elem):
        self.elem = elem
        self.prev = None
        self.next = None

雙向鏈表的實現:

class DoubleNode:
    def __init__(self, elem):
        self.elem = elem
        self.prev = None
        self.next = None


class DoubleLinkedList():
    def __init__(self):
        self.__head = None

    def is_empty(self) -> bool:
        """
        判斷是否爲空
        :return:
        """
        return self.__head is None

    def length(self) -> int:
        """
        鏈表的長度
        :return:count
        """
        # 如果是空鏈表直接就返回count=0
        cur = self.__head
        count = 0
        while cur is not None:
            count += 1
            cur = cur.next
        return count

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

    def add(self, item):
        """
        頭插法
        :param item:
        :return:
        """
        node = DoubleNode(item)
        if self.is_empty():
            self.__head = node
            return
        node.next = self.__head
        self.__head = node
        node.next.prev = node

    def append(self, elem):
        """
        尾部添加元素
        :param elem:
        :return:
        """
        node = DoubleNode(elem)
        if self.is_empty():
            self.__head = node
        else:
            cur = self.__head
            while cur.next is not None:
                cur = cur.next
            cur.next = node
            node.prev = cur

    def insert(self, pos, elem):
        node = DoubleNode(elem)
        if pos <= 0:
            self.add(elem)
        elif pos > self.length() - 1:
            self.append(elem)
        else:
            cur = self.__head
            count = 0
            while count < pos:
                cur = cur.next
                count += 1
            # 第一種方式
            node.next = cur
            node.prev = cur.prev
            cur.prev.next = node
            cur.prev = node
            # 第二種方式
            """
            cur.prev = node
            node.prev.next = node
            """

    def search(self, elem) -> bool:
        cur = self.__head
        while cur is not None:
            if cur.elem == elem:
                return True
            else:
                cur = cur.next
        return False

    def remove(self, elem):
        cur = self.__head
        while cur is not None:
            if cur.elem == elem:
                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


dll = DoubleLinkedList()
print('-------初始的鏈表------')
print('當前鏈表是否爲空:', dll.is_empty())
print('當前鏈表的長度:', dll.length())
print('------頭插法添加鏈表------')
dll.add(1)
dll.add(2)
dll.add(3)
print('當前鏈表是否爲空:', dll.is_empty())
print('當前鏈表的長度:', dll.length())
print('遍歷鏈表:', end='')
dll.travel()
print('\n------尾插法添加鏈表------')
dll.append(1)
dll.append(2)
dll.append(3)
dll.append(4)
print('當前鏈表是否爲空:', dll.is_empty())
print('當前鏈表的長度:', dll.length())
print('遍歷鏈表:', end='')
dll.travel()
print('\n------指定位置插入------')
dll.insert(0, 6)
dll.insert(2, 7)
dll.insert(5, 8)
print('當前鏈表是否爲空:', dll.is_empty())
print('當前鏈表的長度:', dll.length())
print('遍歷鏈表:', end='')
dll.travel()
print('\n------查找元素------')
print('當前鏈表是否爲空:', dll.is_empty())
print('當前鏈表的長度:', dll.length())
print('遍歷鏈表:', end='')
dll.travel()
print('\n鏈表中是否存在元素是2的節點:%s' % dll.search(2))
print('------刪除元素(這裏以刪除頭節點6爲例子)------')
dll.remove(6)
print('當前鏈表是否爲空:', dll.is_empty())
print('當前鏈表的長度:', dll.length())
print('遍歷鏈表:', end='')
dll.travel()
"""
-------初始的鏈表------
當前鏈表是否爲空: True
當前鏈表的長度: 0
------頭插法添加鏈表------
當前鏈表是否爲空: False
當前鏈表的長度: 3
遍歷鏈表:3 2 1 
------尾插法添加鏈表------
當前鏈表是否爲空: False
當前鏈表的長度: 7
遍歷鏈表:3 2 1 1 2 3 4 
------指定位置插入------
當前鏈表是否爲空: False
當前鏈表的長度: 10
遍歷鏈表:6 3 7 2 1 8 1 2 3 4 
------查找元素------
當前鏈表是否爲空: False
當前鏈表的長度: 10
遍歷鏈表:6 3 7 2 1 8 1 2 3 4 
鏈表中是否右元素是2的節點:True
------刪除元素------
當前鏈表是否爲空: False
當前鏈表的長度: 9
遍歷鏈表:3 7 2 1 8 1 2 3 4 
"""
5. 單向循環鏈表

單鏈表的一個變形是單向循環鏈表,鏈表中最後一個節點的next域不再爲None,而是指向鏈表的頭節點。
在這裏插入圖片描述
節點的創建:

class Node:
    def __init__(self, elem):
        self.elem = elem
        self.next = None

單向循環鏈表的實現:

class Node:
    def __init__(self, elem):
        self.elem = elem
        self.next = None


class CircularlinkedList:
    def __init__(self, node=None):
        self.__head = node
        if node:
            node.next = node

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

    def lencllth(self):
        """
        獲取鏈表的長度
        :return:
        """
        # 如果是空鏈表
        if self.is_empty():
            return 0
        # 只有一個節點,也是可以處理的
        cur = self.__head
        count = 1
        while cur.next != self.__head:
            count += 1
            cur = cur.next
        return count

    def travel(self):
        """
        遍歷所有節點中的元素
        :return:
        """
        # 如果是空鏈表則不作任何操作
        if self.is_empty():
            return
        # 如果只有一個節點也是可以處理的
        cur = self.__head
        while cur.next != self.__head:
            print(cur.elem, end=' ')
            cur = cur.next
        print(cur.elem)

    def add(self, elem):
        """
        頭部插入
        :param elem:
        :return:
        """
        node = Node(elem)
        # 如果是空鏈表
        if self.is_empty():
            self.__head = node
            node.next = node
            return
        # 只有一個節點,也是可以處理的
        cur = self.__head
        while cur.next != self.__head:
            cur = cur.next
        node.next = self.__head
        self.__head = node
        # cur.next = node
        cur.next = self.__head

    def append(self, elem):
        """
        尾部插入
        :param elem:
        :return:
        """
        node = Node(elem)
        # 鏈表爲空
        if self.is_empty():
            self.__head = node
            node.next = node
            return
        # 也適用於鏈表只有一個節點
        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, elem):
        if pos <= 0:
            self.add(elem)
        elif pos > self.lencllth() - 1:
            self.append(elem)
        else:
            # 因爲不涉及頭節點和尾節點的鏈接,中間插入和單鏈表插入方式一樣
            count = 0
            pre = self.__head
            while count < pos - 1:
                count += 1
                pre = pre.next
            # 循環退出之後,pre指向post-1的位置
            node = Node(elem)
            node.next = pre.next
            pre.next = node

    def search(self, elem):
        if self.is_empty():
            return False
        cur = self.__head
        while cur != self.__head:
            if cur.elem == elem:
                return True
            cur = cur.next
        if cur.elem == elem:
            return True
        return False

    def remove(self, elem):
        if self.is_empty():
            return
        cur = self.__head
        prev = None
        while cur.next != self.__head:
            if cur.elem == elem:
                # 判斷是否是頭節點
                if cur == self.__head:
                    rear = self.__head
                    # 通過循環找到尾節點
                    while rear.next != self.__head:
                        rear = rear.next
                    self.__head = cur.next
                    rear.next = self.__head
                else:
                    # 刪除中間節點
                    prev.next = cur.next
                return
            prev = cur
            cur = cur.next
        # 上述循環之後,最後一個節點的元素沒有判斷,所以需要判斷
        if cur.elem == elem:
            # 如果鏈表只有一個節點
            if cur.next == self.__head:
                self.__head = None
            # prev.next = cur.next
            prev.next = self.__head


cll = CircularlinkedList()
print('------鏈表初始化信息-----')
print('當前鏈表是否爲空:', cll.is_empty())
print('當前鏈表長度:', cll.lencllth())
print('------在鏈表尾部添加節點------')
cll.append(1)
cll.append(2)
cll.append(3)
cll.append(4)
cll.append(5)
cll.append(6)
print('當前鏈表是否爲空:', cll.is_empty())
print('當前鏈表長度:', cll.lencllth())
print('遍歷鏈表:', end='')
cll.travel()
print('\n------在鏈表頭部添加節點-----')
cll.add(7)
print('當前鏈表是否爲空:', cll.is_empty())
print('當前鏈表長度:', cll.lencllth())
print('遍歷鏈表:', end='')
cll.travel()
print('\n------在指定位置插入節點-----')
cll.insert(0, 8)
cll.insert(2, 9)
cll.insert(9, 10)
cll.insert(10, 10)
print('當前鏈表是否爲空:', cll.is_empty())
print('當前鏈表長度:', cll.lencllth())
print('遍歷鏈表:', end='')
cll.travel()
print('\n------刪除指定位置的元素,實現的效果類似列表的remove方法-----')
cll.remove(8)
cll.remove(1)
cll.remove(10)
print('當前鏈表是否爲空:', cll.is_empty())
print('當前鏈表長度:', cll.lencllth())
print('遍歷鏈表:', end='')
cll.travel()
"""
------鏈表初始化信息-----
當前鏈表是否爲空: True
當前鏈表長度: 0
------在鏈表尾部添加節點------
當前鏈表是否爲空: False
當前鏈表長度: 6
遍歷鏈表:1 2 3 4 5 6

------在鏈表頭部添加節點-----
當前鏈表是否爲空: False
當前鏈表長度: 7
遍歷鏈表:7 1 2 3 4 5 6

------在指定位置插入節點-----
當前鏈表是否爲空: False
當前鏈表長度: 11
遍歷鏈表:8 7 9 1 2 3 4 5 6 10 10

------刪除指定位置的元素,實現的效果類似列表的remove方法-----
當前鏈表是否爲空: False
當前鏈表長度: 8
遍歷鏈表:7 9 2 3 4 5 6 10
"""

Github:https://github.com/ThanlonSmith/Data-Structure-Python3

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