在编程的世界里,数据结构是构建算法的基石,也是优化代码效率的灵魂。无论是解决括号匹配的经典问题,还是设计高并发的任务调度系统,栈、队列、双端队列 等基础结构始终扮演着关键角色。而链表作为动态内存管理的“魔术师”,更是从底层逻辑上展现了数据存储的灵活性与智慧。
目录
一、栈(Stack)
特性:
先进后出(LIFO),仅允许在栈顶操作。
优势:
操作高效:插入(push
)和删除(pop
)的时间复杂度均为O(1)
内存紧凑:顺序表实现时空间利用率高,适合局部操作频繁的场景
缺点:
访问受限:无法直接访问非栈顶元素,需遍历弹出
溢出风险:深度递归或大规模压栈可能导致栈溢出
适用场景:
括号匹配
函数调用栈(递归调用、中断处理)
撤销操作(如文本编辑器的“撤销”功能)。
实现:
class Stack :
def __init__(self):
self.stack = [ ]
def is_empty(self):
return len(self.stack) == 0
def push(self , element):
self.stack.append( element )
def pop(self):
if not self.is_empty() :
return self.stack.pop( )
raise IndexError(" Pop from empty stack ! " )
def size(self):
return len( self.stack )
def peek(self):
return self.stack[ -1 ] if not self.is_empty() else None
二、队列(Queue)
特性:
先进先出(FIFO),队尾插入(enqueue
)、队首删除(dequeue
)。
优势:
顺序管理:保证任务按提交顺序执行,适合公平调度
线程安全:常用于生产者-消费者模型,缓冲异步任务
缺点:
访问限制:仅能操作两端,中间元素无法直接访问
空间浪费:数组实现时可能因循环队列设计产生空闲块
适用场景:
任务调度(如打印队列、消息队列)
广度优先搜索(BFS)的层序遍历
实现:
from collections import deque
class Queue :
def __init__(self):
self.queue = deque( )
def is_empty(self):
return len( self.queue ) == 0
def enqueue(self , element):
self.queue.append( element )
def dequeue(self):
if not self.is_empty() :
return self.queue.popleft()
raise IndexError( " Pop from empty queue ! " )
def front(self):
return self.queue[ 0 ] if not self.is_empty() else None
def size(self):
return len(self.queue)
三、双端队列(Deque)
特性:
两端均可插入和删除,结合栈和队列的特性
优势:
操作灵活:insertFront
和insertLast
均支持O(1)操作
空间高效:循环数组实现可避免内存碎片
缺点:
实现复杂:需处理边界条件(如数组越界、链表指针维护)
额外开销:双向链表实现时需存储前后指针,内存占用较高
适用场景:
滑动窗口算法
缓存淘汰策略(如LRU缓存的双端链表实现)
任务优先级动态调整(如操作系统中断处理)
实现:
from collections import deque
class Deque :
def __init__(self):
self.deque = deque( )
def is_empty(self):
return len( self.deque ) == 0
def add_front(self , element):
self.deque.appendleft( element )
def add_rear(self , element):
self.deque.append( element )
def remove_front(self):
if not self.is_empty() :
return self.deque.popleft()
raise IndexError( "Pop from empty deque ! " )
def remove_rear(self):
if not self.is_empty() :
return self.deque.pop()
raise IndexError( "Pop from empty deque ! " )
def front(self):
return self.deque[ 0 ] if not self.is_empty() else None
def rear(self):
return self.deque[ -1 ] if not self.is_empty() else None
def size(self):
return len( self.deque )
四、单向链表(Singly Linked List)
特性:
节点包含数据和指向下一个节点的指针,动态分配内存
优势:
动态扩展:无需连续内存,适合数据规模不确定的场景
增删高效:插入/删除节点仅需修改指针,时间复杂度O(1)
缺点:
查询低效:访问第k个元素需遍历,时间复杂度O(n)
空间浪费:每个节点需额外存储指针,内存占用高于数组
适用场景:
高频增删(如实时日志记录)
实现其他结构(如栈、队列、图邻接表)
实现:
#定义节点
class ListNode :
def __init__(self , data):
self.data = data
self.next = None
#基本操作
class SinglyLinkedList :
def __init__(self):
#初始化空链表
self.head = None
#头插法添加节点
def insert_head( self , data ) :
new_node = ListNode( data )
new_node.next = self.head
self.head = new_node
#尾插法添加节点
def insert_tail( self , data ):
new_node = ListNode( data )
if not self.head : #存疑,标记
self.head = new_node
return
current = self.head
while current.next :
current = current.next
current.next = new_node
#删除节点
def delete(self,data):
if not self.head :
return
if self.head.data == data :
self.head = self.head.next
return
current = self.head
while current.next :
if current.next.data == data :
current.next = current.next.next
return
current = current.next
#遍历链表
def traverse(self):
current = self.head
while current :
print( current.data ,end ='->')
current = current.next
print('None')
li = SinglyLinkedList( )
li.insert_head(56)
li.insert_tail(345)
li.insert_head(4)
li.delete(345)
li.traverse()
#4->56->None
五、双向链表(Doubly Linked List)
特性:
节点包含前驱和后继指针,支持双向遍历
优势:
回溯便捷:可快速访问前驱节点,适合需要逆向操作的场景
删除高效:已知节点时删除操作仅需O(1)时间(无需遍历前驱)
缺点:
内存翻倍:每个节点多存储一个指针,空间开销较单向链表高30%
维护复杂:插入/删除需同时修改前驱和后继指针
适用场景:
浏览器历史管理(前进/后退功能)
复杂数据结构(如红黑树节点、跳表)
实现:
class DoublyListNode :
def __init__(self,data):
self.data = data
self.prev = None
self.next = None
class DoublyLinkedList :
def __init__(self):
self.head = None
def insert_head (self,data) :
new_node = DoublyListNode( data )
if not self.head :
self.head = new_node
return
new_node.next = self.head
self.head.prev = new_node
self.head = new_node
def insert_tail (self,data) :
new_node = DoublyListNode( data )
if not self.head :
self.head = new_node
return
current = self.head
while current.next :
current = current.next
current.next = new_node
new_node.prev = current
def delete_data(self,data):
if not self.head :
return
if self.head.data == data :
self.head = self.head.next
if self.head : #确保新的头节点存在
self.head.prev = None
return
current = self.head
while current.next :
if current.next.data == data :
current.next = current.next.next
if current.next :
current.next.prev = current
return
else :
current = current.next
def delete_node(self,node):
if node.prev :
node.prev.next = node.next
else :
self.head = node.next
if node.next :
node.next.prev = node.prev
def traverse_forward(self):
current = self.head
print('(head)None',end='<->')
while current :
print(current.data,end = '<->')
current = current.next
print('(tail)None')
def traverse_backward(self):
if not self.head:
print('(tail)None<->(head)None')
current = self.head
while current.next :
current = current.next
print('(tail)None',end='<->')
while current :
print(current.data,end = '<->')
current = current.prev
print('(head)None')
doubly_linked_list = DoublyLinkedList( )
doubly_linked_list.insert_head(55)
doubly_linked_list.insert_head(45)
doubly_linked_list.insert_head(34)
doubly_linked_list.insert_tail(12)
doubly_linked_list.insert_tail(22)
doubly_linked_list.insert_tail(34)
doubly_linked_list.insert_head(23)
doubly_linked_list.delete_data(23)
doubly_linked_list.delete_data(45)
doubly_linked_list.insert_tail(88)
doubly_linked_list.traverse_forward()
doubly_linked_list.delete_data(88)
doubly_linked_list.traverse_backward()
# (head)None<->34<->55<->12<->22<->34<->88<->(tail)None
# (tail)None<->34<->22<->12<->55<->34<->(head)None