线性结构(Linear Structures) 1. 顺序存储 列表(List) 元组(Tuple) 字符串(String) 2. 线性存储 栈(Stack) 队列(Queue) 双端队列(Deque,Double-Ended Queue) 优先队列(Priority Queue)/ 最小堆 非线性结构(Non-Linear Structures) 1. 哈希表 2. 树结构 二叉树(Binary Tree) 平衡二叉树(AVL 树 / 红黑树) Trie(字典树 / 前缀树) 3. 图(Graph) networkx 图论库 并查集(Union-Find) 特殊结构 跳表(Skip List) Bloom Filter(布隆过滤器) LRU 缓存(Least Recently Used Cache) 总结:如何选择数据结构?
Python 的数据结构可以根据 存储方式、访问方式、适用场景 等进行分类。
线性结构(Linear Structures)
1. 顺序存储
数据结构 说明 适用场景 列表(List) Python 内置 动态数组 ,支持 索引访问 适用于 动态数组、查找、排序 元组(Tuple) 不可变 的列表,性能优于 List 适用于 只读数据、键值映射 字符串(String) Python 视为 不可变的字符数组 适用于 文本处理
列表(List)
可变 (Mutable):可以修改、添加或删除元素。有序 (Ordered):元素按插入顺序存储,可通过索引访问。支持重复元素 :允许存储相同的值。动态大小 :可以随时增减元素。
方法 说明 append(x)
在列表 末尾添加元素 x
extend(iterable)
用可迭代对象 iterable
扩展列表 insert(i, x)
在索引 i
处插入元素 x
remove(x)
删除列表中 第一个值为 x
的元素 pop([i])
删除并返回索引 i
处的元素,默认 删除最后一个 clear()
清空 列表index(x, [start, end])
返回 元素 x
在列表中的索引 ,可指定范围 count(x)
统计 元素 x
在列表中出现的次数 sort(key=None, reverse=False)
对列表进行 排序 ,可指定 key
和是否降序 reverse()
反转 列表copy()
返回列表的 浅拷贝
my_list = [ 3 , 1 , 4 , 1 , 5 , 9 , 2 ]
my_list. append( 6 )
my_list. extend( [ 7 , 8 , 9 ] )
my_list. insert( 2 , 42 )
my_list. remove( 1 )
popped_element = my_list. pop( )
index_of_5 = my_list. index( 5 )
count_of_1 = my_list. count( 1 )
my_list. sort( )
my_list. reverse( )
copy_list = my_list. copy( )
my_list. clear( )
元组(Tuple)
不可变 (Immutable):创建后不能修改元素值。有序 :可以通过索引访问。支持重复元素 。占用更少内存 ,比列表更快。
方法 说明 count(x)
统计 元素 x
在元组中出现的次数 index(x, [start, end])
返回 元素 x
在元组中第一次出现的索引 ,可指定范围
my_tuple = ( 3 , 1 , 4 , 1 , 5 , 9 , 2 , 6 , 5 , 3 , 5 )
count_of_5 = my_tuple. count( 5 )
index_of_9 = my_tuple. index( 9 )
index_of_5_in_range = my_tuple. index( 5 , 3 , 9 )
相比于 List,元组的不可变性使其缺少修改数据的方法 ,例如 append()
、remove()
、insert()
等操作。如果 需要修改数据,可以转换成 List,修改后再转换回 Tuple 。
虽然 元组的方法只有 count()
和 index()
。 但仍可以使用 +
、*
、切片、内置函数 等方式进行操作。 +
连接(拼接) tuple1 = ( 1 , 2 , 3 )
tuple2 = ( 4 , 5 , 6 )
new_tuple = tuple1 + tuple2
*
复制 tuple1 = ( 1 , 2 , 3 )
tuple2 = tuple1 * 2
字符串(String)
不可变 (Immutable):一旦创建,字符串的内容不可修改。有序 (Ordered):字符串中的字符按顺序排列,可以通过索引访问。支持重复字符 :允许出现相同的字符。固定大小 :字符串的长度一旦确定,就不能再修改。
方法 说明 upper()
将字符串中的 所有字母 转换为 大写 lower()
将字符串中的 所有字母 转换为 小写 capitalize()
将字符串的 第一个字符 转换为 大写 ,其余字符转换为 小写 title()
将字符串中的 每个单词的首字母 转换为 大写 strip()
移除字符串 两端的空白字符 (包括空格、换行符等) replace(old, new)
将字符串中的 old
字符替换为 new
字符 split(separator)
使用 指定的分隔符 将字符串分割成一个 列表 ,默认为按空白字符分割 join(iterable)
将 可迭代对象 (如列表)中的元素连接成一个字符串 find(sub)
返回子字符串 sub
在字符串中 首次出现的位置 ,若未找到返回 -1 count(sub)
返回子字符串 sub
在字符串中出现的 次数 index(sub)
返回子字符串 sub
在字符串中 首次出现的位置 ,若未找到则抛出异常 startswith(prefix)
判断字符串是否以指定的 prefix
开头 endswith(suffix)
判断字符串是否以指定的 suffix
结尾 isalpha()
判断字符串是否只包含 字母 isdigit()
判断字符串是否只包含 数字 isalnum()
判断字符串是否只包含 字母和数字
my_string = " Hello, Python! "
upper_str = my_string. upper( )
lower_str = my_string. lower( )
capitalized_str = my_string. capitalize( )
title_str = my_string. title( )
stripped_str = my_string. strip( )
replaced_str = my_string. replace( "Python" , "World" )
split_list = my_string. split( )
joined_str = "-" . join( split_list)
index_of_python = my_string. find( "Python" )
count_python = my_string. count( "Python" )
index_of_world = my_string. index( "World" )
starts_with_hello = my_string. startswith( "Hello" )
ends_with_exclamation = my_string. endswith( "!" )
is_alpha = "abc" . isalpha( )
is_alpha_num = "abc123" . isalpha( )
is_digit = "12345" . isdigit( )
is_alnum = "abc123" . isalnum( )
2. 线性存储
数据结构 说明 适用场景 栈(Stack) 后进先出(LIFO) ,用 list.append()
& list.pop()
实现撤销操作、括号匹配、深度优先搜索(DFS) 队列(Queue) 先进先出(FIFO) ,用 collections.deque
实现任务调度、消息队列 双端队列(Deque) 两端可进可出 ,用 collections.deque
实现滑动窗口、缓存管理 优先队列(Priority Queue) 元素按优先级排列 ,用 heapq
实现调度系统、最短路径算法(Dijkstra)
栈(Stack)
后进先出(LIFO, Last In First Out) 只能在一端 进行插入和删除(称为栈顶
) 操作类似于“堆叠的盘子”,后放的盘子要先取出
方法 说明 stack.append(x)
入栈(Push) :将元素 x
压入栈顶stack.pop()
出栈(Pop) :移除并返回栈顶元素stack[-1]
查看栈顶元素(Peek) len(stack)
查看栈的大小 not stack
判断栈是否为空
stack = [ ]
stack. append( 1 )
stack. append( 2 )
stack. append( 3 )
print ( "Stack after push:" , stack)
top = stack[ - 1 ]
print ( "Top element:" , top)
popped = stack. pop( )
print ( "Popped element:" , popped)
print ( "Stack after pop:" , stack)
print ( "Is stack empty?" , not stack)
print ( "Stack size:" , len ( stack) )
高效栈用 deque
实现 。
from collections import dequestack = deque( ) stack. append( 1 )
stack. append( 2 )
stack. append( 3 )
print ( stack. pop( ) )
print ( stack)
队列(Queue)
先进先出(FIFO, First In First Out) 从队尾入队,从队首出队 操作类似于“排队买票”,先来的人先买票离开
方法 说明 queue.append(x)
入队(Enqueue) :将元素 x
插入队尾queue.pop(0)
出队(Dequeue) :移除并返回队首元素queue[0]
查看队首元素(Peek) len(queue)
查看队列大小 not queue
判断队列是否为空
queue = [ ]
queue. append( "A" )
queue. append( "B" )
queue. append( "C" )
print ( "Queue after enqueue:" , queue)
front = queue[ 0 ]
print ( "Front element:" , front)
dequeued = queue. pop( 0 )
print ( "Dequeued element:" , dequeued)
print ( "Queue after dequeue:" , queue)
print ( "Is queue empty?" , not queue)
print ( "Queue size:" , len ( queue) )
高效队列用 deque
实现 。
queue = deque( ) queue. append( "A" )
queue. append( "B" )
queue. append( "C" )
print ( queue. popleft( ) )
print ( queue)
双端队列(Deque,Double-Ended Queue)
两端插入和删除都是 O ( 1 ) O(1) O ( 1 ) 的时间复杂度 (比 list.pop(0)
快)适用于队列和栈的双重需求
方法 说明 deque.append(x)
右端入队 (等同于 list.append(x)
)deque.appendleft(x)
左端入队 deque.pop()
右端出队 deque.popleft()
左端出队 deque.extend(iterable)
批量右端入队 deque.extendleft(iterable)
批量左端入队 (注意:会逆序 插入)deque.rotate(n)
循环右移 n
位 (n
为负数则左移)deque.reverse()
原地反转队列 deque.clear()
清空队列
from collections import deque
dq = deque( [ 1 , 2 , 3 ] )
dq. append( 4 )
dq. appendleft( 0 )
dq. pop( )
dq. popleft( )
dq. extend( [ 4 , 5 ] )
dq. extendleft( [ - 1 , - 2 ] )
dq. rotate( 2 )
dq. rotate( - 1 )
dq. reverse( )
dq. clear( )
优先队列(Priority Queue)/ 最小堆
优先队列是一种 按照优先级顺序存储元素 的数据结构,Python 提供 heapq
模块来实现 最小堆(Min-Heap) ,默认情况下 最小值优先出队 。
元素按照优先级排序,默认最小值优先 插入和删除的时间复杂度为 O ( l o g n ) O(log\ n) O ( l o g n ) 适用于任务调度、路径搜索(Dijkstra 算法)等
方法 说明 heapq.heappush(heap, x)
入队 (x
加入 heap
并保持最小堆)heapq.heappop(heap)
出队 (移除并返回最小元素)heapq.heappushpop(heap, x)
先入队,再出队最小值 (比 push
+pop
快)heapq.heapify(iterable)
将列表转换为最小堆 heapq.nlargest(n, heap)
获取前 n
个最大元素 (不会改变堆)heapq.nsmallest(n, heap)
获取前 n
个最小元素 (不会改变堆)
import heapq
pq = [ ]
heapq. heappush( pq, 3 )
heapq. heappush( pq, 1 )
heapq. heappush( pq, 4 )
heapq. heappush( pq, 2 )
print ( "After heappush:" , pq)
min_item = heapq. heappop( pq)
print ( "heappop():" , min_item)
print ( "After heappop:" , pq)
nums = [ 9 , 5 , 7 , 2 , 6 ]
heapq. heapify( nums)
print ( "heapify():" , nums)
result = heapq. heappushpop( pq, 0 )
print ( "heappushpop(0):" , result)
print ( "After heappushpop:" , pq)
largest = heapq. nlargest( 2 , pq)
smallest = heapq. nsmallest( 2 , pq)
print ( "nlargest(2):" , largest)
print ( "nsmallest(2):" , smallest)
非线性结构(Non-Linear Structures)
1. 哈希表
数据结构 说明 适用场景 字典(Dict) 键值对存储 ,O(1) 查询索引、缓存、数据存储 集合(Set) 无序、不重复 ,O(1) 查询去重、集合运算
哈希表(Hash Table)/ 哈希映射(Hash Map)特点 :
通过 键值对(key-value) 存储数据 平均 O(1) 的查找、插入和删除 Python 的 dict
本质上是一个 哈希表 hash_map = { }
hash_map[ "name" ] = "Alice"
hash_map[ "age" ] = 25
print ( hash_map[ "name" ] )
print ( hash_map. get( "age" , "Not Found" ) )
字典(Dictionary)
键值对存储 (Key-Value):类似 JavaScript 的对象。无序(Python 3.6 之前),有序(Python 3.7+) :Python 3.7+ 中,字典保持插入顺序。键唯一 :不能有重复的键。
方法 说明 dict.keys()
返回 所有键 的 dict_keys
视图 dict.values()
返回 所有值 的 dict_values
视图 dict.items()
返回 键值对 的 dict_items
视图 dict.get(key, default)
返回 key 对应的值 ,若 key 不存在返回 default
dict.pop(key, default)
删除 key 并返回对应的值 ,若 key 不存在返回 default
dict.popitem()
随机删除并返回(Python 3.7+ 为删除最后插入的键值对 ) dict.update(other_dict)
合并字典 ,若 key 已存在,则覆盖其值dict.setdefault(key, default)
获取 key 对应的值 ,若 key 不存在,则添加 default
dict.clear()
清空 字典dict.copy()
返回字典的 浅拷贝
完整示例 :
my_dict = { "name" : "Alice" , "age" : 25 , "city" : "New York" }
print ( "keys():" , my_dict. keys( ) )
print ( "values():" , my_dict. values( ) )
print ( "items():" , my_dict. items( ) )
print ( "get('age'):" , my_dict. get( "age" ) )
print ( "get('gender', 'Not Found'):" , my_dict. get( "gender" , "Not Found" ) )
age = my_dict. pop( "age" )
print ( "pop('age'):" , age, my_dict)
last_item = my_dict. popitem( )
print ( "popitem():" , last_item, my_dict)
my_dict. update( { "gender" : "Female" , "age" : 26 } )
print ( "setdefault('city', 'Los Angeles'):" , my_dict. setdefault( "city" , "Los Angeles" ) )
print ( "After setdefault:" , my_dict)
copy_dict = my_dict. copy( )
my_dict. clear( )
集合(Set)
无序 (Unordered):元素没有固定的顺序。不允许重复元素 (Unique)。支持集合运算 (交集、并集、差集等)。
方法 说明 set.add(x)
添加元素 x
到集合set.remove(x)
删除元素 x
,如果 x
不存在,则抛出 KeyError
set.discard(x)
删除元素 x
,如果 x
不存在,不报错set.pop()
随机删除 并返回一个元素(由于无序性 ,不确定删除哪个)set.clear()
清空集合 set.copy()
复制集合 set.update(iterable)
用可迭代对象 扩展集合 set.union(other_set)
并集 (返回新集合)set.intersection(other_set)
交集 (返回新集合)set.difference(other_set)
差集 (返回新集合)set.symmetric_difference(other_set)
对称差集 (返回新集合)set.issubset(other_set)
判断是否为 子集 (返回 True/False
) set.issuperset(other_set)
判断是否为 超集 (返回 True/False
) set.isdisjoint(other_set)
判断两个集合是否 无交集 (返回 True/False
)
完整示例 :
my_set = { 1 , 2 , 3 , 4 , 5 }
another_set = { 3 , 4 , 5 , 6 , 7 } print ( my_set & another_set)
print ( my_set | another_set)
my_set. add( 6 )
my_set. remove( 6 )
my_set. discard( 10 )
popped_item = my_set. pop( )
print ( "pop():" , popped_item, my_set)
my_set. clear( )
copy_set = another_set. copy( )
my_set. update( [ 1 , 2 , 3 ] )
union_set = my_set. union( another_set)
intersection_set = my_set. intersection( another_set)
difference_set = my_set. difference( another_set)
symmetric_diff_set = my_set. symmetric_difference( another_set)
print ( "issubset(another_set):" , { 3 } . issubset( my_set) )
print ( "issuperset({3}):" , my_set. issuperset( { 3 } ) )
print ( "isdisjoint({10, 11}):" , my_set. isdisjoint( { 10 , 11 } ) )
2. 树结构
数据结构 说明 适用场景 二叉树(Binary Tree) 每个节点最多两个子节点 表达式解析、层次遍历 二叉搜索树(BST) 有序存储,O(log n) 查询 排序、搜索 AVL 树 / 红黑树 自平衡二叉搜索树 ,O(log n) 操作数据库索引、C++ map
/set
Trie(字典树) 字符串前缀存储,O(m) 查询 搜索引擎、拼写检查
二叉树(Binary Tree)
二叉树 (Binary Tree),是一种 每个节点最多有两个子节点 的数据结构。二叉树并 没有对节点值的排列做任何特殊限制 。
二叉查找树 是二叉树的一种特例,它要求节点的值必须满足如下条件:
对于任何节点 node
,node
的左子树中的所有节点值都比 node
的值小 。 对于任何节点 node
,node
的右子树中的所有节点值都比 node
的值大 。
这种排列使得查找、插入和删除操作能以 O ( l o g n ) O(log\ n) O ( l o g n ) 的时间复杂度进行(在树平衡的情况下)。
平衡二叉树(AVL 树 / 红黑树)
自平衡 的二叉搜索树,确保 O(log n) 查找、插入、删除 Python sortedcontainers
库可以用于 平衡树结构 Python 的 dict
和 set
底层使用哈希表 ,但 C++ 的 map/set
是 红黑树
sortedcontainers
是一个第三方库,提供了高效的排序容器,支持自动平衡。这个库实现了 平衡二叉树(如 AVL 树 / 红黑树) 的功能,允许 O(log n) 的插入、删除和查找操作。
方法 说明 SortedList
类似于列表,但元素始终保持排序。 add(value)
向 SortedList
中添加一个元素,并保持排序。 remove(value)
从 SortedList
中移除一个元素。 bisect_left(value)
查找元素插入的位置,返回第一个大于等于 value
的索引位置。 bisect_right(value)
查找元素插入的位置,返回第一个严格大于 value
的索引位置。 index(value)
返回 value
元素的索引位置,如果不存在则抛出异常。 __getitem__(index)
获取指定索引处的元素。 __delitem__(index)
删除指定索引处的元素。 __contains__(value)
判断元素是否在 SortedList
中。 pop(index)
弹出指定索引处的元素,删除并返回该元素。 __iter__()
迭代遍历 SortedList
中的元素。 __len__()
返回 SortedList
中的元素个数。
from sortedcontainers import SortedList
sorted_list = SortedList( )
sorted_list. add( 10 )
sorted_list. add( 5 )
sorted_list. add( 20 )
sorted_list. add( 15 ) print ( "SortedList after adding elements:" )
print ( sorted_list)
sorted_list. remove( 10 )
print ( "SortedList after removing 10:" )
print ( sorted_list)
print ( "Index of 15:" , sorted_list. index( 15 ) )
print ( "Bisect left for 12:" , sorted_list. bisect_left( 12 ) )
print ( "Bisect right for 12:" , sorted_list. bisect_right( 12 ) )
print ( "Does SortedList contain 15?" , 15 in sorted_list)
print ( "Does SortedList contain 10?" , 10 in sorted_list)
print ( "Element at index 1:" , sorted_list[ 1 ] )
popped_element = sorted_list. pop( 1 )
print ( "Popped element:" , popped_element)
print ( "SortedList after pop:" )
print ( sorted_list)
print ( "Iterating over SortedList:" )
for item in sorted_list: print ( item, end= " " )
print ( "\nNumber of elements in SortedList:" , len ( sorted_list) )
Trie(字典树 / 前缀树)
用于 高效的字符串查找 (如自动补全、字典存储) 查找时间复杂度为 O(m) (m 是字符串长度)适用于 搜索引擎、字典匹配、DNA 序列匹配
class TrieNode : def __init__ ( self) : self. children = { } self. is_end = False class Trie : def __init__ ( self) : self. root = TrieNode( ) def insert ( self, word) : node = self. rootfor char in word: if char not in node. children: node. children[ char] = TrieNode( ) node = node. children[ char] node. is_end = True def search ( self, word) : node = self. rootfor char in word: if char not in node. children: return False node = node. children[ char] return node. is_endtrie = Trie( )
trie. insert( "hello" )
print ( trie. search( "hello" ) )
print ( trie. search( "hell" ) )
3. 图(Graph)
由顶点(Nodes) 和 边(Edges) 组成 可以是 有向图 / 无向图 ,支持 加权 / 无权 广泛用于社交网络、地图导航、网络路由等
数据结构 说明 适用场景 邻接表(Adjacency List) 用 dict
存储邻接关系 社交网络、地图路径 邻接矩阵(Adjacency Matrix) 用 list[list]
存储连接关系 稠密图、动态规划 并查集(Union-Find) 快速合并 & 查找集合 连通性检测、最小生成树(MST)
networkx 图论库
方法 说明 Graph()
创建一个空的无向图 add_node(node)
向图中 添加一个节点 add_nodes_from(nodes)
向图中 添加多个节点 add_edge(u, v, weight=w)
向图中 添加一条边 ,(从节点 u
到节点 v
),权重为 w
(可选) add_edges_from(ebunch, weight=w)
向图中 添加多条边 ,所有边的权重为 w
(可选) remove_node(node)
删除一个节点 (删除节点及其相关边)remove_edge(u, v)
删除一条边 has_node(node)
判断图中是否包含节点 node
has_edge(u, v)
判断图中是否包含从 u
到 v
的边 nodes()
返回图中 所有节点 edges(data=True)
返回图中 所有边 ,data=True
包括权重(可选) get_edge_data(u, v)
获取从 u
到 v
的 边的属性 ,包括权重 set_edge_attributes(G, values, name='weight')
设置图 G
中所有边的 权重 (或其他属性) degree(node)
返回节点 node
的 度数 (连接到该节点的边的数目) neighbors(n)
返回节点 n
的 所有邻居节点 adjacency()
返回图的 邻接列表 shortest_path(source, target, weight='weight')
返回从 source
到 target
的 最短路径 (权重可选) shortest_path_length(source, target, weight='weight')
返回从 source
到 target
的 最短路径长度 (权重可选) diameter()
返回图的 直径 (最长最短路径的长度) center()
返回图的 中心节点 (距离最远节点最短的节点) closeness_centrality(node)
返回节点 node
的 接近中心性 betweenness_centrality(node)
返回节点 node
的 介数中心性 pagerank()
返回图的 PageRank 值 is_connected()
判断图是否 连通 draw()
绘制图的 可视化 (需要 Matplotlib) draw_networkx_edge_labels()
在绘图时 显示边的权重 subgraph(nodes)
返回一个包含指定节点的 子图 set_edge_attributes(G, values, name='weight')
设置边的属性(例如权重)
import networkx as nx
import matplotlib. pyplot as plt
G = nx. Graph( )
G. add_edge( 1 , 2 , weight= 4.2 )
G. add_edges_from( [ ( 2 , 3 , { 'weight' : 2.5 } ) , ( 3 , 4 , { 'weight' : 7.1 } ) ] )
print ( "Edges with weights:" , G. edges( data= True ) )
edge_weight = G[ 1 ] [ 2 ] [ 'weight' ]
print ( "Weight of edge (1, 2):" , edge_weight)
G[ 1 ] [ 2 ] [ 'weight' ] = 9.0
print ( "Updated weight of edge (1, 2):" , G[ 1 ] [ 2 ] [ 'weight' ] )
edge_data = G. get_edge_data( 1 , 2 )
print ( "Edge data for (1, 2):" , edge_data)
print ( "All edges with data:" , list ( G. edges( data= True ) ) )
shortest_path = nx. shortest_path( G, source= 1 , target= 4 , weight= 'weight' )
print ( "Shortest path from 1 to 4:" , shortest_path)
shortest_path_length = nx. shortest_path_length( G, source= 1 , target= 4 , weight= 'weight' )
print ( "Shortest path length from 1 to 4:" , shortest_path_length)
pos = nx. spring_layout( G)
labels = nx. get_edge_attributes( G, 'weight' )
nx. draw( G, pos, with_labels= True , node_color= 'lightblue' , node_size= 2000 , font_size= 15 )
nx. draw_networkx_edge_labels( G, pos, edge_labels= labels)
plt. show( )
print ( "Diameter of the graph:" , nx. diameter( G) )
print ( "Center of the graph:" , nx. center( G) )
print ( "Closeness centrality of node 2:" , nx. closeness_centrality( G, 2 ) )
print ( "Betweenness centrality of node 2:" , nx. betweenness_centrality( G) [ 2 ] )
print ( "PageRank values:" , nx. pagerank( G) )
subgraph = G. subgraph( [ 1 , 2 , 3 ] )
print ( "Subgraph nodes:" , subgraph. nodes( ) )
并查集(Union-Find)
高效合并(Union)和查找(Find) ,用于动态连通性 问题主要用于 图的连通性检测、最小生成树(Kruskal)、网络连接等 路径压缩 + 按秩合并 可以优化到 O(α(n)) ≈ O(1)
class UnionFind : def __init__ ( self, n) : self. parent = list ( range ( n) ) def find ( self, x) : if self. parent[ x] != x: self. parent[ x] = self. find( self. parent[ x] ) return self. parent[ x] def union ( self, x, y) : rootX = self. find( x) rootY = self. find( y) if rootX != rootY: self. parent[ rootX] = rootY uf = UnionFind( 5 )
uf. union( 0 , 1 )
uf. union( 1 , 2 )
print ( uf. find( 0 ) == uf. find( 2 ) )
特殊结构
数据结构 说明 适用场景 跳表(Skip List) O(log n) 查询,链表+多级索引 有序集合(Redis)、区间查询 布隆过滤器(Bloom Filter) 概率型结构,快速检测元素是否存在 黑名单过滤、去重 LRU 缓存(Least Recently Used Cache) 自动移除最久未使用的数据 网页缓存、CPU缓存
跳表(Skip List)
通过 多层链表结构 提供 O(log n) 搜索 ,类似于平衡二叉树 建立 多层次的索引 ,允许在 每一层上进行跳跃式的查找 用于 高效的区间查询、排序数据结构 Redis 的 有序集合(SortedSet) 采用 跳表实现
方法 说明 insert(value)
插入值为 value
的新节点。 search(value)
查找值为 value
的节点,若存在返回节点,否则返回 None
。 delete(value)
删除值为 value
的节点。 random_level()
生成一个随机层级,用于决定新节点的高度。 print_list()
打印跳表的层次结构。
import randomclass Node : def __init__ ( self, value, level) : self. value = value self. forward = [ None ] * ( level + 1 ) class SkipList : def __init__ ( self, max_level= 16 , p= 0.5 ) : self. max_level = max_level self. p = p self. header = Node( None , self. max_level) self. level = 0 def random_level ( self) : level = 0 while random. random( ) < self. p and level < self. max_level: level += 1 return leveldef insert ( self, value) : update = [ None ] * ( self. max_level + 1 ) current = self. headerfor i in range ( self. level, - 1 , - 1 ) : while current. forward[ i] and current. forward[ i] . value < value: current = current. forward[ i] update[ i] = currentcurrent = current. forward[ 0 ] if current and current. value == value: return new_level = self. random_level( ) if new_level > self. level: for i in range ( self. level + 1 , new_level + 1 ) : update[ i] = self. headerself. level = new_levelnew_node = Node( value, new_level) for i in range ( new_level + 1 ) : new_node. forward[ i] = update[ i] . forward[ i] update[ i] . forward[ i] = new_nodedef search ( self, value) : current = self. headerfor i in range ( self. level, - 1 , - 1 ) : while current. forward[ i] and current. forward[ i] . value < value: current = current. forward[ i] current = current. forward[ 0 ] return current if current and current. value == value else None def delete ( self, value) : update = [ None ] * ( self. max_level + 1 ) current = self. headerfor i in range ( self. level, - 1 , - 1 ) : while current. forward[ i] and current. forward[ i] . value < value: current = current. forward[ i] update[ i] = currentcurrent = current. forward[ 0 ] if current and current. value == value: for i in range ( self. level + 1 ) : if update[ i] . forward[ i] != current: break update[ i] . forward[ i] = current. forward[ i] while self. level > 0 and not self. header. forward[ self. level] : self. level -= 1 def print_list ( self) : for i in range ( self. level + 1 ) : current = self. header. forward[ i] print ( f"Level { i} : " , end= "" ) while current: print ( current. value, end= " -> " ) current = current. forward[ i] print ( "None" )
skip_list = SkipList( )
skip_list. insert( 3 )
skip_list. insert( 6 )
skip_list. insert( 7 )
skip_list. insert( 9 )
skip_list. insert( 12 )
skip_list. insert( 19 )
skip_list. insert( 17 )
skip_list. print_list( )
print ( skip_list. search( 6 ) )
print ( skip_list. search( 15 ) )
skip_list. delete( 6 )
skip_list. print_list( )
Bloom Filter(布隆过滤器)
高效存储和检测集合中的元素 ,但可能产生误判 (可能会错误地认为某个元素存在)适用于 去重、黑名单检测 不能 删除元素 用于 Google Chrome 安全浏览、Redis 缓存去重
每个元素通过多个哈希函数计算出多个哈希值,将这些哈希值对应的位数组位置标记为 True
。 查询时,再次通过哈希函数计算出这些位置,若所有位置均为 True
,则认为元素可能存在 ;若 有任一位置为 False
,则元素肯定不存在 。
方法 说明 add(item)
将元素 item
添加到布隆过滤器中。 contains(item)
检查元素 item
是否在布隆过滤器中,返回 True
或 False
。
import hashlibclass BloomFilter : def __init__ ( self, size, num_hashes) : self. size = size self. num_hashes = num_hashes self. bit_array = [ False ] * size def _hash ( self, item, seed) : """ 基于给定种子的哈希函数 """ return int ( hashlib. md5( ( str ( seed) + item) . encode( ) ) . hexdigest( ) , 16 ) % self. sizedef add ( self, item) : """ 添加元素到布隆过滤器 """ for i in range ( self. num_hashes) : index = self. _hash( item, i) self. bit_array[ index] = True def contains ( self, item) : """ 检查元素是否在布隆过滤器中 """ for i in range ( self. num_hashes) : index = self. _hash( item, i) if not self. bit_array[ index] : return False return True
bloom = BloomFilter( size= 1000 , num_hashes= 5 )
bloom. add( "apple" )
bloom. add( "banana" )
bloom. add( "cherry" )
print ( bloom. contains( "apple" ) )
print ( bloom. contains( "banana" ) )
print ( bloom. contains( "orange" ) )
LRU 缓存(Least Recently Used Cache)
最近最少使用 ,即 使用频率最低的元素最先被淘汰 Python functools.lru_cache
提供了现成实现 适用于缓存系统,如 CPU 缓存、网页缓存
示例 (使用 OrderedDict
实现 LRU 缓存):
from collections import OrderedDictclass LRUCache : def __init__ ( self, capacity) : self. cache = OrderedDict( ) self. capacity = capacitydef get ( self, key) : if key not in self. cache: return - 1 self. cache. move_to_end( key) return self. cache[ key] def put ( self, key, value) : if key in self. cache: self. cache. move_to_end( key) self. cache[ key] = valueif len ( self. cache) > self. capacity: self. cache. popitem( last= False ) lru = LRUCache( 2 )
lru. put( 1 , "A" )
lru. put( 2 , "B" )
print ( lru. get( 1 ) )
lru. put( 3 , "C" )
print ( lru. get( 2 ) )
总结:如何选择数据结构?
需要快速查询? → 哈希表(dict
)、集合(set
)、Trie 需要顺序存储? → list
(动态数组)、tuple
需要按顺序处理? → 栈(LIFO)、队列(FIFO)、优先队列 需要排序查找? → 二叉搜索树(BST)、跳表 需要高效合并? → 并查集 需要图结构? → 邻接表、邻接矩阵 需要去重检测? → 布隆过滤器 需要缓存管理? → LRU 缓存
数据结构 可变性 有序性 是否允许重复元素 典型应用 列表(List) 可变 有序 允许 适合存储 序列 数据 元组(Tuple) 不可变 有序 允许 适合存储 固定 数据 字典(Dictionary) 可变 有序(3.7+) 键 不能重复映射关系(Key-Value) 存储集合(Set) 可变 无序 不允许 去重、集合 运算栈(Stack) 可变 有序 允许 后进先出 (LIFO)队列(Queue) 可变 有序 允许 先进先出 (FIFO)