Python实现单链表、单循环链表、双链表及双循环链表

文章目录

  • 前言
  • 单链表
  • 单循环链表
  • 双链表
  • 双循环链表
  • 错误纠正说明
  • 时间复杂度比较
  • 关于头结点

前言

博主最近在复习算法与数据结构,由于平时主力语言是Python,所以找了个用Python讲解数据结构的视频看了下,链接为:https://www.bilibili.com/video/av20982396?p=1。
关于链表,视频里讲的很清楚,但是代码有几处小错误,现将其代码纠正,并添加视频里没有讲到的双循环链表代码。
那么我们直接上代码吧。

单链表

class Node(object):
    """单链表结点"""
    def __init__(self, elem):
        self.elem = elem
        self.next = None


class SinglyLinkedList(object):
    def __init__(self, node=None):
        self.__head = node

    def is_empty(self):
        """判断链表是否为空"""
        return self.__head is None

    def length(self):
        """返回链表长度"""
        cur = self.__head
        count = 0
        while cur is not None:
            count += 1
            cur = cur.next
        return count

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

    def add(self, elem):
        """向链表头部添加元素"""
        node = Node(elem)
        node.next = self.__head
        self.__head = node

    def append(self, elem):
        """向链表尾部添加元素"""
        node = Node(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):
        """向链表位置pos处插入元素

        Args:
            pos: 插入位置,从0开始计数
            elem: 需要插入的元素
        """
        if pos <= 0:
            self.add(elem)
        elif pos > (self.length() - 1):
            self.append(elem)
        else:
            pre = self.__head
            count = 0
            while count < (pos-1):
                count += 1
                pre = pre.next
            # 当循环退出后,pre指向pos-1位置
            node = Node(elem)
            node.next = pre.next
            pre.next = node

    def remove(self, elem):
        """从链表中删除第一个值为elem的元素"""
        cur = self.__head
        pre = None
        while cur is not None:
            if cur.elem == elem:
                if cur == self.__head:
                    self.__head = cur.next
                else:
                    pre.next = cur.next
                break
            else:
                pre = cur
                cur = cur.next

    def search(self, elem):
        """查找链表中是否存在元素elem"""
        cur = self.__head
        while cur is not None:
            if cur.elem == elem:
                return True
            else:
                cur = cur.next
        return False


if __name__ == '__main__':
    singly_linked_list = SinglyLinkedList()
    print(singly_linked_list.is_empty())
    print(singly_linked_list.length())
    print('===================')

    singly_linked_list.append(1)
    print(singly_linked_list.is_empty())
    print(singly_linked_list.length())
    print('===================')

    singly_linked_list.append(2)
    singly_linked_list.append(3)

    singly_linked_list.add(7)

    singly_linked_list.append(4)
    singly_linked_list.append(5)

    singly_linked_list.insert(0, 13)  # 13, 7, 1, 2, 3, 4, 5
    singly_linked_list.travel()

    singly_linked_list.insert(2, 99)  # 13, 7, 99, 1, 2, 3, 4, 5
    singly_linked_list.travel()

    singly_linked_list.insert(11, 22)  # 13, 7, 99, 1, 2, 3, 4, 5, 22
    singly_linked_list.travel()

    singly_linked_list.remove(13)
    singly_linked_list.travel()  # 7 99 1 2 3 4 5 22

    singly_linked_list.remove(22)
    singly_linked_list.travel()  # 7 99 1 2 3 4 5

    singly_linked_list.remove(3)
    singly_linked_list.travel()  # 7 99 1 2 4 5

    print(singly_linked_list.search(1000))  # False
    print(singly_linked_list.search(7))  # True
    print(singly_linked_list.search(5))  # True
    print(singly_linked_list.search(2))  # True

如上所示,测试代码已经在main函数中给出了。

单循环链表

class Node(object):
    def __init__(self, elem):
        """单循环链表结点"""
        self.elem = elem
        self.next = None


class SinglyLinkedCircularList(object):
    """单向循环链表"""
    def __init__(self, node=None):
        self.__head = node
        if node:
            node.next = node

    def is_empty(self):
        """判断链表是否为空"""
        return self.__head is None

    def length(self):
        """求链表长度"""
        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):
        """遍历链表"""
        if self.is_empty():
            return
        cur = self.__head
        while cur.next != self.__head:
            print(cur.elem, end=' ')
            cur = cur.next
        # 退出循环时,cur指向最后一个结点
        print(cur.elem)

    def add(self, elem):
        """向链表头部添加元素"""
        node = Node(elem)
        if self.is_empty():
            node.next = node
            self.__head = node
        else:
            cur = self.__head
            while cur.next != self.__head:
                cur = cur.next
            node.next = self.__head
            self.__head = node
            cur.next = node

    def append(self, elem):
        """向链表尾部添加元素"""
        node = Node(elem)
        if self.is_empty():
            node.next = node
            self.__head = node
        else:
            cur = self.__head
            while cur.next != self.__head:
                cur = cur.next
            node.next = self.__head
            cur.next = node

    def insert(self, pos, elem):
        """向链表位置pos处插入元素

        Args:
            pos: 插入的位置,从0开始计数
            elem: 插入的元素
        """
        if pos <= 0:
            self.add(elem)
        elif pos > (self.length() - 1):
            self.append(elem)
        else:
            pre = self.__head
            count = 0
            while count < (pos - 1):
                count += 1
                pre = pre.next
            # 退出循环,pre指向插入位置的前一个结点
            node = Node(elem)
            node.next = pre.next
            pre.next = node

    def remove(self, elem):
        """删除链表中第一个为elem的元素"""
        if self.is_empty():
            return
        cur = self.__head
        pre = 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
                    rear.next = cur.next
                    self.__head = cur.next
                else:  # 中间结点
                    pre.next = cur.next
                return
            else:
                pre = cur
                cur = cur.next
        # 退出循环, cur指向尾结点
        if cur.elem == elem:
            # 链表中只有一个结点
            if cur == self.__head:
                self.__head = None
            else:
                pre.next = self.__head

    def search(self, elem):
        """查找链表中是否存在元素elem"""
        if self.is_empty():
            return False
        cur = self.__head
        while cur.next != self.__head:
            if cur.elem == elem:
                return True
            else:
                cur = cur.next
        # 退出循环,cur指向尾结点
        if cur.elem == elem:
            return True
        return False


if __name__ == '__main__':
    singly_linked_circular_list = SinglyLinkedCircularList()
    print(singly_linked_circular_list.is_empty())
    print(singly_linked_circular_list.length())
    print('===================')

    singly_linked_circular_list.append(1)
    print(singly_linked_circular_list.is_empty())
    print(singly_linked_circular_list.length())
    print('===================')

    singly_linked_circular_list.append(2)
    singly_linked_circular_list.append(3)

    singly_linked_circular_list.add(7)

    singly_linked_circular_list.append(4)
    singly_linked_circular_list.append(5)

    singly_linked_circular_list.insert(0, 13)  # 13, 7, 1, 2, 3, 4, 5
    singly_linked_circular_list.travel()

    singly_linked_circular_list.insert(2, 99)  # 13, 7, 99, 1, 2, 3, 4, 5
    singly_linked_circular_list.travel()

    singly_linked_circular_list.insert(11, 22)  # 13, 7, 99, 1, 2, 3, 4, 5, 22
    singly_linked_circular_list.travel()

    singly_linked_circular_list.remove(13)
    singly_linked_circular_list.travel()  # 7 99 1 2 3 4 5 22

    singly_linked_circular_list.remove(22)
    singly_linked_circular_list.travel()  # 7 99 1 2 3 4 5

    singly_linked_circular_list.remove(3)
    singly_linked_circular_list.travel()  # 7 99 1 2 4 5

    print(singly_linked_circular_list.search(666))  # False
    print(singly_linked_circular_list.search(7))  # True
    print(singly_linked_circular_list.search(5))  # True
    print(singly_linked_circular_list.search(1))  # True

双链表

class Node(object):
    def __init__(self, elem):
        """双链表结点"""
        self.elem = elem
        self.pre = None
        self.next = None


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

    def is_empty(self):
        """判断链表是否为空"""
        return self.__head is None

    def length(self):
        """获取链表长度"""
        cur = self.__head
        count = 0
        while cur is not None:
            count += 1
            cur = cur.next
        return count

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

    def add(self, elem):
        """向双链表头部添加元素"""
        node = Node(elem)
        if self.is_empty():  # 链表为空
            self.__head = node
        else:
            node.next = self.__head
            node.next.pre = node
            self.__head = node

    def append(self, elem):
        """向链表尾部添加结点"""
        node = Node(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.pre = cur

    def insert(self, pos, elem):
        """向链表位置pos处插入元素elem"""
        if pos <= 0:
            self.add(elem)
        elif pos > (self.length() - 1):
            self.append(elem)
        else:
            cur = self.__head
            count = 0
            while count < pos:
                count += 1
                cur = cur.next
            # 退出循环时,cur即为pos位置
            node = Node(elem)
            node.next = cur
            node.pre = cur.pre
            cur.pre.next = node
            cur.pre = node

    def remove(self, elem):
        """删除链表中第一个值为elem的结点"""
        if self.is_empty():
            return
        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.pre = None
                else:
                    cur.pre.next = cur.next
                    if cur.next:  # 如果不是尾结点
                        cur.next.pre = cur.pre
                break
            else:
                cur = cur.next

    def search(self, elem):
        """查找链表中是否存在元素elem"""
        cur = self.__head
        while cur is not None:
            if cur.elem == elem:
                return True
            else:
                cur = cur.next
        return False


if __name__ == '__main__':
    double_linked_list = DoubleLinkedList()
    print(double_linked_list.is_empty())
    print(double_linked_list.length())
    print('===================')

    double_linked_list.append(1)
    print(double_linked_list.is_empty())
    print(double_linked_list.length())
    print('===================')

    double_linked_list.append(2)
    double_linked_list.append(3)

    double_linked_list.add(7)

    double_linked_list.append(4)
    double_linked_list.append(5)

    double_linked_list.insert(0, 13)  # 13, 7, 1, 2, 3, 4, 5
    double_linked_list.travel()

    double_linked_list.insert(2, 99)  # 13, 7, 99, 1, 2, 3, 4, 5
    double_linked_list.travel()

    double_linked_list.insert(11, 22)  # 13, 7, 99, 1, 2, 3, 4, 5, 22
    double_linked_list.travel()

    double_linked_list.remove(13)
    double_linked_list.travel()  # 7 99 1 2 3 4 5 22

    double_linked_list.remove(22)
    double_linked_list.travel()  # 7 99 1 2 3 4 5

    double_linked_list.remove(3)
    double_linked_list.travel()  # 7 99 1 2 4 5

    print(double_linked_list.search(100))  # False
    print(double_linked_list.search(7))  # True
    print(double_linked_list.search(2))  # True
    print(double_linked_list.search(5))  # True

双循环链表

class Node(object):
    """双循环链表结点"""
    def __init__(self, elem):
        self.elem = elem
        self.pre = None
        self.next = None
    

class DoubleLinkedCircularList(object):
    def __init__(self, node=None):
        self.__head = node
        if node:
            node.next = node
    
    def is_empty(self):
        """判断链表是否为空"""
        return self.__head is None
    
    def length(self):
        """求取链表长度"""
        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):
        """遍历链表"""
        if self.is_empty():
            return
        cur = self.__head
        while cur.next != self.__head:
            print(cur.elem, end=' ')
            cur = cur.next
        # 退出循环,cur指向尾结点
        print(cur.elem)
    
    def add(self, elem):
        """向链表头部添加元素"""
        node = Node(elem)
        if self.is_empty():
            self.__head = node
            node.next = node
        else:
            cur = self.__head
            while cur.next != self.__head:
                cur = cur.next
            # 退出循环,cur指向尾结点
            cur.next = node
            node.next = self.__head
            self.__head.pre = node
            self.__head = node
    
    def append(self, elem):
        """向链表尾部添加元素"""
        node = Node(elem)
        if self.is_empty():
            self.__head = node
            node.next = node
        else:
            cur = self.__head
            while cur.next != self.__head:
                cur = cur.next
            # 退出循环,cur指向尾结点
            cur.next = node
            node.pre = cur
            node.next = self.__head
    
    def insert(self, pos, elem):
        """往双向循环链表位置pos处插入元素

        Args:
            pos: 插入位置
            elem: 插入的元素
        """
        if pos <= 0:
            self.add(elem)
        elif pos > (self.length() - 1):
            self.append(elem)
        else:
            cur = self.__head
            count = 0
            while count < pos:
                count += 1
                cur = cur.next
            # 退出循环,cur指向需要插入的位置pos
            node = Node(elem)
            node.next = cur
            node.pre = cur.pre
            cur.pre.next = node
            cur.pre = node
    
    def remove(self, elem):
        """删除链表中第一个值为elem的结点"""
        if self.is_empty():
            return
        cur = self.__head
        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
                    self.__head.pre = None
                    rear.next = self.__head
                else:  # 删除的是中间结点
                    cur.next.pre = cur.pre
                    cur.pre.next = cur.next
                return
            else:
                cur = cur.next
        # 退出循环,cur指向尾结点
        if cur.elem == elem:
            if cur == self.__head:  # 链表中只有一个结点
                self.__head = None
            else:
                cur.pre.next = self.__head
    
    def search(self, elem):
        """查找链表中是否存在值为elem的结点"""
        if self.is_empty():
            return False
        cur = self.__head
        while cur.next != self.__head:
            if cur.elem == elem:
                return True
            else:
                cur = cur.next
        # 退出循环,cur指向尾结点
        if cur.elem == elem:
            return True
        return False


if __name__ == '__main__':
    double_linked_circular_list = DoubleLinkedCircularList()
    print(double_linked_circular_list.is_empty())
    print(double_linked_circular_list.length())
    print('===================')

    double_linked_circular_list.append(1)
    print(double_linked_circular_list.is_empty())
    print(double_linked_circular_list.length())
    print('===================')

    double_linked_circular_list.append(2)
    double_linked_circular_list.append(3)

    double_linked_circular_list.add(7)

    double_linked_circular_list.append(4)
    double_linked_circular_list.append(5)
    double_linked_circular_list.travel()  # 7, 1, 2, 3, 4, 5

    double_linked_circular_list.insert(0, 13)  # 13, 7, 1, 2, 3, 4, 5
    double_linked_circular_list.travel()

    double_linked_circular_list.insert(2, 99)  # 13, 7, 99, 1, 2, 3, 4, 5
    double_linked_circular_list.travel()

    double_linked_circular_list.insert(11, 22)  # 13, 7, 99, 1, 2, 3, 4, 5, 22
    double_linked_circular_list.travel()

    double_linked_circular_list.remove(13)
    double_linked_circular_list.travel()  # 7 99 1 2 3 4 5 22

    double_linked_circular_list.remove(22)
    double_linked_circular_list.travel()  # 7 99 1 2 3 4 5

    double_linked_circular_list.remove(3)
    double_linked_circular_list.travel()  # 7 99 1 2 4 5

    print(double_linked_circular_list.search(100))  # False
    print(double_linked_circular_list.search(7))  # True
    print(double_linked_circular_list.search(2))  # True
    print(double_linked_circular_list.search(5))  # True

错误纠正说明

对于单链表、单循环链表、双链表代码纠正了视频里两处错误:

    def insert(self, pos, elem):
        if pos < 0:
            self.add(elem)

纠正为现在的:

    def insert(self, pos, elem):
        if pos <= 0:
            self.add(elem)

双链表add(self, elem)方法由原来的:

	def add(self, elem):
		"""向双链表头部添加元素"""
		node = Node(elem)
		node.next = self.__head
		self.__head = node
		node.next.pre = node

纠正为现在的:

    def add(self, elem):
    	"""向双链表头部添加元素"""
        node = Node(elem)
        if self.is_empty():  # 链表为空
            self.__head = node
        else:
            node.next = self.__head
            node.next.pre = node
            self.__head = node

如果代码中还有其他错误,或者我改错了欢迎读者朋友们评论区指证,我会及时纠正。

时间复杂度比较

操作 单链表 单循环链表 双链表 双向循环链表
初始化 O ( 1 ) O(1) O(1) O ( 1 ) O(1) O(1) O ( 1 ) O(1) O(1) O ( 1 ) O(1) O(1)
判空 O ( 1 ) O(1) O(1) O ( 1 ) O(1) O(1) O ( 1 ) O(1) O(1) O ( 1 ) O(1) O(1)
求长度 O ( n ) O(n) O(n) O ( n ) O(n) O(n) O ( n ) O(n) O(n) O ( n ) O(n) O(n)
遍历 O ( n ) O(n) O(n) O ( n ) O(n) O(n) O ( n ) O(n) O(n) O ( n ) O(n) O(n)
头部插入/删除元素 O ( 1 ) O(1) O(1) O ( n ) O(n) O(n) O ( 1 ) O(1) O(1) O ( n ) O(n) O(n)
尾部插入/删除元素 O ( n ) O(n) O(n) O ( n ) O(n) O(n) O ( n ) O(n) O(n) O ( n ) O(n) O(n)
中间插入/删除元素 O ( n ) O(n) O(n) O ( n ) O(n) O(n) O ( n ) O(n) O(n) O ( n ) O(n) O(n)
查找元素 O ( n ) O(n) O(n) O ( n ) O(n) O(n) O ( n ) O(n) O(n) O ( n ) O(n) O(n)

可以看到,除了在头部插入/删除元素外,各种链表的其他操作的时间复杂度都是一样的。循环链表因为尾结点的next域(类似C++中的指针)要指向头结点,所以每当在头部插入/删除元素时,都需要遍历链表找到尾结点从而修改其next域,这样就提高了时间复杂度。

关于头结点

需要说明的是,文章上述部分以及代码中所提到的头结点应该叫做首元结点(链表中第一个元素所在的结点)会更为准确。
通常我们说的头结点是首元结点之前的一个结点,它的数据域可以不去定义,也可以存储链表长度等信息。而这个时候头指针就指向头结点而不是首元结点了。也就是说链表的头指针始终保存的是链表的地址,无论这个链表有没有头结点。
设置头结点的主要作用为(参考链接):

  • 对带头结点的链表,在表的任何结点之前插入结点或删除表中任何结点,所要做的都是修改前一结点的指针域,因为任何元素结点都有前驱结点。若链表没有头结点,则首元素结点没有前驱结点,在其前插入结点或删除该结点时操作会复杂些。
  • 对带头结点的链表,头指针是指向头结点的非空指针,因此空表与非空表的处理是一样的。
    详细信息还可以参考这篇文章:链表头结点存在的意义
    然后关于头结点的使用我们再看一道牛客网上的题目吧:

如果一个链表的最常用的操作是在末尾插入结点和删除结点,则选用()最节省时间。
A. 带头结点的双循环链表
B. 单循环链表
C. 带尾指针的单循环链表
D. 单链表

这道题的答案应该是A。A中可以利用头结点的数据域存储尾结点的地址,那么每次插入和删除就可以直接访问尾结点,时间复杂度为 O ( 1 ) O(1) O(1)。而其他三种链表中,单链表和单循环链表插入时都需要找到尾结点,时间复杂度为 O ( n ) O(n) O(n),而带尾指针的单循环链表插入元素时间复杂度为 O ( 1 ) O(1) O(1)。在末尾删除元素时,剩下的三种链表都需要找到倒数第二个结点,时间复杂度为 O ( n ) O(n) O(n)。综上,选择A最节省时间。
该题在牛客网上的链接:题目讨论

你可能感兴趣的:(python,数据结构与算法)