Skip to content

数据结构

数据结构

1 链表(Linked List)

链表是一种线性数据结构,由一系列节点组成,每个节点包含两个部分:数据部分和指向下一个节点的指针。链表的优势是插入和删除操作较为高效,不需要移动大量元素。链表的类型有单向链表、双向链表和循环链表。

基本概念:
链表(Linked List)是一种由节点构成的线性数据结构,其中每个节点包含两个部分:

  • 数据域:存储数据;
  • 指针域:存储下一个节点的地址(或引用);

链表类型:

  • 单向链表(Singly Linked List):每个节点只包含指向下一个节点的指针,最后一个节点的指针为 None,表示链表结束;
  • 双向链表(Doubly Linked List):每个节点包含两个指针:一个指向下一个节点,另一个指向上一个节点。这样可以从链表的两端进行遍历;
  • 循环链表(Circular Linked List):链表的最后一个节点指向头节点,形成一个环状结构。循环链表可以是单向的,也可以是双向的;

链表操作

  • 插入节点:可以在头部、尾部或中间位置插入节点;
  • 删除节点:删除头部、尾部或中间位置的节点;
  • 查找节点:通过遍历链表查找特定的节点;
  • 修改节点:根据索引或节点数据修改节点的值;
  • 遍历链表:访问每个节点的数据;

链表优缺点

  • 优点:
  • 动态大小,不需要预先分配内存;
  • 插入和删除操作效率高,特别是在链表的头部或中间;

  • 缺点:

  • 访问元素需要遍历,查找元素的时间复杂度为 O(n);
  • 相比于数组,内存利用率较低(每个节点需要额外的指针存储空间);

1.1 单向链表(Singly Linked List)

单向链表是最简单的链表类型。每个节点包含两部分:

  • 数据域(Data):存储节点的数据;
  • 指针域(Next):存储指向下一个节点的指针;

特点:

  • 只能从头节点向后遍历;
  • 插入和删除操作较为高效,尤其是头部和中间的操作;
  • 需要O(n)的时间复杂度来访问节点(通过遍历);

示例:

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
class Node:
    """
    表示链表中的一个节点,包含 data(存储数据)和 next(指向下一个节点的引用)属性
    """
    def __init__(self, data):
        self.data = data  # 节点的数据
        self.next = None  # 指向下一个节点的指针

class SinglyLinkedList:
    """
    表示整个链表,提供了插入、删除、查找和打印链表的功能
    """
    def __init__(self):
        self.head = None  # 链表的头节点

    def insert_at_head(self, data):
        """在头部插入一个节点"""
        new_node = Node(data)
        new_node.next = self.head  # 新节点指向当前头节点
        self.head = new_node  # 更新头节点

    def insert_at_tail(self, data):
        """在尾部插入一个节点"""
        new_node = Node(data)
        if not self.head:  # 如果链表为空
            self.head = new_node
            return
        last = self.head
        while last.next:  # 找到最后一个节点
            last = last.next
        last.next = new_node  # 最后一个节点的next指向新节点

    def delete_node(self, key):
        """删除特定值节点"""
        temp = self.head
        if temp and temp.data == key:  # 如果头节点是删除目标节点
            self.head = temp.next
            temp = None
            return

        # 查找要删除的节点
        prev = None
        while temp and temp.data != key:
            prev = temp
            temp = temp.next
        if not temp:  # 未找到目标节点
            return
        prev.next = temp.next  # 删除节点
        temp = None

    # 查找一个节点
    def search(self, key):
        temp = self.head
        while temp:
            if temp.data == key:
                return True
            temp = temp.next
        return False

    def print_list(self):
        """遍历并打印链表"""
        temp = self.head
        while temp:
            print(temp.data, end=" -> ")
            temp = temp.next
        print("None")

# 示例:使用链表
linked_list = SinglyLinkedList()

# 插入节点
linked_list.insert_at_head(10)
linked_list.insert_at_head(20)
linked_list.insert_at_tail(30)
linked_list.print_list()  # 输出: 20 -> 10 -> 30 -> None

# 删除节点
linked_list.delete_node(10)
linked_list.print_list()  # 输出: 20 -> 30 -> None

# 查找节点
print(linked_list.search(20))  # 输出: True
print(linked_list.search(40))  # 输出: False

1.2 双向链表 (Doubly Linked List)

双向链表比单向链表更复杂。每个节点包含三个部分:

  • 数据域(Data):存储节点的数据;
  • 指向下一个节点的指针(Next);
  • 指向上一个节点的指针(Prev);

特点:

  • 可以从头节点或尾节点双向遍历;
  • 插入和删除操作更加灵活,可以从任意位置(头部、尾部、任意节点)进行高效操作;
  • 需要更多的内存,因为每个节点有两个指针;

示例代码:

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
class DoublyNode:
    def __init__(self, data):
        self.data = data  # 节点的数据
        self.next = None  # 指向下一个节点的指针
        self.prev = None  # 指向上一个节点的指针

class DoublyLinkedList:
    def __init__(self):
        self.head = None  # 链表的头节点

    def insert_at_head(self, data):
        """在头部插入一个节点"""
        new_node = DoublyNode(data)
        if self.head:
            self.head.prev = new_node
        new_node.next = self.head  # 新节点指向当前头节点
        self.head = new_node  # 更新头节点

    def insert_at_tail(self, data):
        """在尾部插入一个节点"""
        new_node = DoublyNode(data)
        if not self.head:  # 如果链表为空
            self.head = new_node
            return
        last = self.head
        while last.next:  # 找到最后一个节点
            last = last.next
        last.next = new_node  # 最后一个节点的next指向新节点
        new_node.prev = last  # 新节点的prev指向当前的最后一个节点

    def delete_node(self, key):
        """删除指定值的节点"""
        temp = self.head
        if temp and temp.data == key:  # 如果要删除的是头节点
            self.head = temp.next
            if self.head:
                self.head.prev = None
            temp = None
            return
        while temp:
            if temp.data == key:  # 找到目标节点
                temp.prev.next = temp.next
                if temp.next:
                    temp.next.prev = temp.prev
                temp = None
                return
            temp = temp.next

    def print_list(self):
        """正向遍历并打印链表"""
        temp = self.head
        while temp:
            print(temp.data, end=" <-> ")
            temp = temp.next
        print("None")

# 示例使用
doubly_linked_list = DoublyLinkedList()
doubly_linked_list.insert_at_head(10)
doubly_linked_list.insert_at_head(20)
doubly_linked_list.insert_at_tail(30)
doubly_linked_list.print_list()  # 20 <-> 10 <-> 30 <-> None
doubly_linked_list.delete_node(10)
doubly_linked_list.print_list()  # 20 <-> 30 <-> None

1.3 循环链表 (Circular Linked List)

循环链表的特点是链表的最后一个节点指向头节点,形成一个闭环。循环链表可以是单向的,也可以是双向的。

  • 单向循环链表:每个节点指向下一个节点,最后一个节点指向头节点;
  • 双向循环链表:每个节点有两个指针,一个指向下一个节点,另一个指向上一个节点,最后一个节点指向头节点,头节点指向最后一个节点;

特点:

  • 没有明确的“末尾”节点,可以从任意位置开始循环遍历;
  • 常用于需要循环访问的数据结构,如约瑟夫问题;

示例代码:单向循环链表

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class CircularNode:
    def __init__(self, data):
        self.data = data  # 节点的数据
        self.next = None  # 指向下一个节点的指针

class CircularLinkedList:
    def __init__(self):
        self.head = None  # 链表的头节点

    def insert_at_head(self, data):
        """在头部插入一个节点"""
        new_node = CircularNode(data)
        if not self.head:
            self.head = new_node
            new_node.next = self.head  # 第一个节点指向自己
        else:
            last = self.head
            while last.next != self.head:  # 遍历到最后一个节点
                last = last.next
            last.next = new_node
            new_node.next = self.head  # 新节点指向头节点
            self.head = new_node  # 更新头节点

    def delete_node(self, key):
        """删除指定值的节点"""
        temp = self.head
        if temp and temp.data == key:  # 如果要删除的是头节点
            if temp.next == self.head:  # 如果只有一个节点
                self.head = None
            else:
                last = self.head
                while last.next != self.head:  # 找到最后一个节点
                    last = last.next
                last.next = temp.next  # 将最后一个节点的next指向头节点的下一个节点
                self.head = temp.next  # 更新头节点
            temp = None
            return
        while temp:
            if temp.data == key:
                prev = temp
                prev.next = temp.next
                temp = None
                return
            temp = temp.next
            if temp == self.head:  # 遍历到头节点,结束循环
                break

    def print_list(self):
        """打印循环链表"""
        if not self.head:
            print("Empty list")
            return
        temp = self.head
        while True:
            print(temp.data, end=" -> ")
            temp = temp.next
            if temp == self.head:  # 回到头节点时停止
                break
        print("")

# 示例使用
circular_linked_list = CircularLinkedList()
circular_linked_list.insert_at_head(10)
circular_linked_list.insert_at_head(20)
circular_linked_list.print_list()  # 20 -> 10 -> 
circular_linked_list.delete_node(10)
circular_linked_list.print_list()  # 20 ->

扩展阅读:
(1) Python List