链表(Linked List)

链表(Linked List)简介

链表是另一种常见的线性数据结构,与数组不同,链表的元素在内存中不必连续存储,而是通过指针(或引用)将各个元素连接起来。

基本特性

  1. 动态大小:链表的大小可以动态增长或缩小
  2. 非连续内存:元素可以分散存储在内存中的任何位置
  3. 顺序访问:必须从头节点开始逐个访问,不能随机访问
  4. 节点结构:每个节点包含数据域和指针域(指向下一个节点)

链表的主要类型

  1. 单向链表(Singly Linked List)

    • 每个节点包含数据和指向下一个节点的指针
    • 只能单向遍历
  2. 双向链表(Doubly Linked List)

    • 每个节点包含数据、指向前驱节点的指针和指向后继节点的指针
    • 可以双向遍历
  3. 循环链表(Circular Linked List)

    • 单向链表或双向链表的变种,尾节点指向头节点形成环
    • 单向循环链表:尾节点指向头节点
    • 双向循环链表:尾节点指向头节点,头节点也指向尾节点

链表的操作复杂度

操作 时间复杂度
访问元素 O(n)
插入/删除(已知位置) O(1)
插入/删除(需要查找位置) O(n)
查找元素 O(n)
在头部插入/删除 O(1)
在尾部插入(无尾指针) O(n)
在尾部插入(有尾指针) O(1)
在尾部删除(无尾指针) O(n)
在尾部删除(有尾指针) O(1)(双链表)或O(n)(单链表)

链表的优缺点

优点

  • 动态大小,无需预先知道数据规模
  • 高效的插入和删除操作(特别是已知位置时,如果不知道位置最差的时间复杂度是 O(n))
  • 内存利用率高(不需要连续内存空间)

缺点

  • 访问元素效率低(必须从头开始遍历)
  • 需要额外空间存储指针
  • 缓存不友好(数据分散在内存各处)
  • 实现比数组复杂

链表的典型应用

  1. 实现栈、队列等抽象数据类型
  2. 实现图的邻接表表示
  3. 内存管理系统
  4. 实现哈希表的链地址法
  5. 需要频繁插入删除的场景
  6. 浏览器历史记录(前进后退功能)
  7. 音乐播放列表

单向链表代码实现

class Node:
    """链表节点定义"""
    def __init__(self, data):
        self.data = data
        self.next = None

class LinkedList:
    """单链表实现"""
    def __init__(self):
        self.head = None
    
    def append(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
    
    def delete(self, key):
        """删除包含指定值的节点"""
        curr = self.head
        
        # 如果头节点就是要删除的节点
        if curr and curr.data == key:
            self.head = curr.next
            curr = None
            return
        
        # 查找要删除的节点
        prev = None
        while curr and curr.data != key:
            prev = curr
            curr = curr.next
        
        # 如果找到则删除
        if curr:
            prev.next = curr.next
            curr = None
    
    def update(self, old_data, new_data):
        """更新节点值"""
        curr = self.head
        while curr:
            if curr.data == old_data:
                curr.data = new_data
                return
            curr = curr.next
        print(f"未找到值为 {old_data} 的节点")

# 使用示例
if __name__ == "__main__":
    ll = LinkedList()
    ll.append(1)
    ll.append(2)
    ll.append(3)
    
    print("原始链表:")
    current = ll.head
    while current:
        print(current.data, end=" -> ")
        current = current.next
    print("None")
    
    ll.update(2, 20)
    ll.delete(1)
    
    print("\n修改后的链表:")
    current = ll.head
    while current:
        print(current.data, end=" -> ")
        current = current.next
    print("None")

链表与数组的比较

特性 数组 链表
内存分配 连续 分散
大小 固定(静态数组) 动态
访问方式 随机访问 顺序访问
访问时间复杂度 O(1) O(n)
插入/删除时间复杂度 O(n) O(1)(已知位置)
内存开销 仅数据 数据+指针
缓存友好性

链表和数组各有优劣,选择使用哪种数据结构取决于具体的应用场景和操作需求。

posted @ 2025-04-26 17:34  CyrusHuang  阅读(68)  评论(0)    收藏  举报