以下是关于链表结构、原理及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缓存、图邻接表等
七、常见问题与技巧
- 虚拟头节点:统一处理头节点操作,避免边界判断
- 双指针法:解决寻找中间节点、检测环等问题
- 递归反转链表:
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属性维护节点间关系。掌握这些基础操作后,可进一步解决反转链表、合并有序链表等经典算法问题。