[数据结构]链表(介绍1)

65 阅读3分钟

以下是关于链表结构、原理及Python实现的详细解析:


一、链表的结构与原理

1. 核心定义

  • 节点(Node):链表的基本单元,包含两部分:
    • 数据域:存储实际数据(如整型、字符串等)
    • 指针域:指向下一个节点的引用(单链表)或前驱/后继节点的引用(双向链表)
  • 链式存储:通过节点间的引用将分散在内存中的节点连接成逻辑上的线性序列。
  • 存储内存不连续:因为节点之间是通过指针指向的, 所以,链表数据在内存中存储的时候, 不一定要求内存是连续的

2. 与数组的对比

特性数组链表
内存分配连续内存块动态分散分配
插入/删除效率O(n)(需移动元素)O(1)(仅修改引用)
随机访问效率O(1)(通过索引直接定位)O(n)(必须从头遍历

二、Python实现链表节点

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val    # 数据域
        self.next = next  # 指针域(指向下一个节点)

三、链表基本操作(Python实现)

1. 查找操作

  • 目标:找到特定值的节点或第k个节点
def search(head: ListNode, target: int) -> ListNode:
    curr = head
    while curr:
        if curr.val == target:
            return curr
        curr = curr.next
    return None  # 未找到

2. 删除操作

  • 关键点:定位前驱节点(被删节点的前一个节点)
def delete_node(head: ListNode, target: int) -> ListNode:
    dummy = ListNode(-1)  # 虚拟头节点
    dummy.next = head
    pre, curr = dummy, head
    
    while curr:
        if curr.val == target:
            pre.next = curr.next  # 跳过当前节点
            break
        pre = curr
        curr = curr.next
    return dummy.next  # 返回新链表头

3. 插入操作

  • 头插法(时间复杂度O(1)):
def insert_at_head(head: ListNode, val: int) -> ListNode:
    new_node = ListNode(val)
    new_node.next = head
    return new_node  # 新节点成为头节点
  • 指定位置插入(如在第k个节点后):
def insert_after(prev_node: ListNode, val: int) -> None:
    if not prev_node:
        return
    new_node = ListNode(val)
    new_node.next = prev_node.next
    prev_node.next = new_node

四、操作示例与测试

1. 构建链表
# 创建链表 1 -> 2 -> 3
node1 = ListNode(1)
node2 = ListNode(2)
node3 = ListNode(3)
node1.next = node2
node2.next = node3
2. 删除值为2的节点
new_head = delete_node(node1, 2)
# 链表变为 1 -> 3
3. 在头部插入0
new_head = insert_at_head(node1, 0)
# 链表变为 0 -> 1 -> 3

五、双向链表示例(扩展)

class DoublyListNode:
    def __init__(self, val=0, prev=None, next=None):
        self.val = val
        self.prev = prev  # 指向前驱节点
        self.next = next

# 双向链表删除操作
def delete_doubly_node(node: DoublyListNode) -> None:
    if node.prev:
        node.prev.next = node.next
    if node.next:
        node.next.prev = node.prev

六、链表的优势与适用场景

  • 动态扩容:无需预先分配固定内存
  • 高效增删:仅需修改引用,无需数据搬移
  • 典型应用:实现栈、队列、LRU缓存、图邻接表等

七、常见问题与技巧

  1. 虚拟头节点:统一处理头节点操作,避免边界判断
  2. 双指针法:解决寻找中间节点、检测环等问题
  3. 递归反转链表
def reverse_list(head: ListNode) -> ListNode:
    if not head or not head.next:
        return head
    new_head = reverse_list(head.next)
    head.next.next = head
    head.next = None
    return new_head

通过Python实现链表操作时,需注意对象引用特性(类似指针),并通过next属性维护节点间关系。掌握这些基础操作后,可进一步解决反转链表、合并有序链表等经典算法问题。