数据结构是计算机中组织、管理和存储数据的方式,它决定了数据的逻辑关系、存储效率以及操作性能。简单来说,数据结构是数据元素之间的结构化组织形式,目的是为了更高效地访问、修改和分析数据。
一、数据元素(Data Elements)
- 定义:数据结构中的基本单元,可以是单个值(如整数、字符)或复杂对象(如结构体、类实例)。
- 示例:
- 数组中的每个元素(如
arr
)。 - 链表中的一个节点(包含值和指针)。
- 树中的结点(包含数据及子节点指针)。
- 数组中的每个元素(如
二、数据关系(Data Relationships)
- 定义:数据元素之间的逻辑关联方式,决定结构的访问和操作规则。
- 类型:
- 线性关系:元素按顺序排列(如数组、队列)。
- 示例:数组的索引顺序、队列的先进先出(FIFO)。
- 层次关系:元素形成父子层级(如树、堆)。
- 示例:二叉树的根节点与左右子树。
- 网状关系:元素多对多关联(如图结构)。
- 示例:社交网络中的用户关注关系。
- 线性关系:元素按顺序排列(如数组、队列)。
三、操作方法(Operations)
- 定义:对数据结构进行增删改查等操作的函数或规则,直接影响性能。
- 常见操作:
- 插入(Insert):在特定位置添加元素(链表插入为 O(1),数组为 O(n))。
- 删除(Delete):移除元素并维护结构完整性(如平衡树的旋转操作)。
- 查找(Search):按值或位置获取元素(哈希表 O(1),链表 O(n))。
- 遍历(Traversal):按顺序访问所有元素(树的深度优先、广度优先遍历)。
四、存储结构(Storage Structure)
- 定义:数据元素在内存或磁盘中的物理存储方式,影响空间利用率和操作效率。
- 类型:
- 顺序存储:连续内存分配(如数组、字符串)。
- 特点:支持快速随机访问,但插入/删除效率低。
- 链式存储:通过指针链接非连续内存块(如链表、树)。
- 特点:动态扩展灵活,但访问需遍历指针链。
- 索引存储:附加索引表加速查找(如数据库的 B+ 树索引)。
- 散列存储:利用哈希函数映射位置(如哈希表)。
- 顺序存储:连续内存分配(如数组、字符串)。
五、附加属性(Extended Properties)
- 定义:为优化性能或功能而添加的辅助信息。
- 常见属性:
- 长度/容量:记录当前元素数量(如动态数组的
size
和capacity
)。 - 头尾指针:快速访问首尾元素(如双向链表、队列)。
- 平衡因子:维持树结构的平衡(如 AVL 树的节点高度差)。
- 长度/容量:记录当前元素数量(如动态数组的
六、常见的数据结构
(一)线性数据结构
(1)数组(List)
arr = [1, 2, 3] # 创建数组
arr.append(4) # 尾部追加 → [1,2,3,4](O(1))
arr.insert(1, 5) # 中间插入 → [1,5,2,3,4](O(n))
arr.pop(2) # 删除索引2 → [1,5,3,4](O(n))
(2)链表(Linked List)
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def append(self, data): # 尾部插入(O(n))
new_node = Node(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): # 删除节点(O(n))
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
(3)栈(Stack)
class Stack:
def __init__(self):
self.items = []
def push(self, item): # 入栈(O(1))
self.items.append(item)
def pop(self): # 出栈(O(1))
return self.items.pop() if not self.is_empty() else None
def peek(self): # 查看栈顶(O(1))
return self.items[-1] if self.items else None
# 示例:括号匹配
def is_valid_parentheses(s: str) -> bool:
stack = Stack()
mapping = {')': '(', ']': '[', '}': '{'}
for char in s:
if char in mapping.values():
stack.push(char)
elif stack.is_empty() or stack.pop() != mapping[char]:
return False
return stack.is_empty()
(4)队列(Queue)
from collections import deque
class Queue:
def __init__(self):
self.items = deque()
def enqueue(self, item): # 入队(O(1))
self.items.append(item)
def dequeue(self): # 出队(O(1))
return self.items.popleft() if not self.is_empty() else None
# 示例:广度优先搜索(BFS)
def bfs(graph, start):
visited = set()
queue = Queue()
queue.enqueue(start)
while not queue.is_empty():
node = queue.dequeue()
if node not in visited:
print(node)
visited.add(node)
for neighbor in graph[node]:
queue.enqueue(neighbor)
(二)非线性数据结构
(1)二叉树(Binary Tree)
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
# 中序遍历(递归实现)
def inorder_traversal(root: TreeNode):
if root:
inorder_traversal(root.left)
print(root.value)
inorder_traversal(root.right)
# 示例
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
inorder_traversal(root) # 输出:2 → 1 → 3
(2)哈希表(Hash Table)
# Python字典是哈希表的高效实现
hash_table = {}
hash_table["name"] = "Alice" # 插入(O(1)平均)
age = hash_table.get("age", 25) # 查找(O(1)平均)
del hash_table["name"] # 删除(O(1)平均)
(3)图(Graph)
class Graph:
def __init__(self):
self.adj_list = {}
def add_edge(self, u, v): # 添加边(O(1))
if u not in self.adj_list:
self.adj_list[u] = []
self.adj_list[u].append(v)
def dfs(self, start): # 深度优先遍历(递归)
visited = set()
def _dfs(node):
if node not in visited:
print(node)
visited.add(node)
for neighbor in self.adj_list.get(node, []):
_dfs(neighbor)
_dfs(start)
# 示例
g = Graph()
g.add_edge(0, 1)
g.add_edge(0, 2)
g.add_edge(1, 3)
g.dfs(0) # 输出:0 → 1 → 3 → 2
(三)高级数据结构
(1)堆(Heap)
import heapq
# 最小堆实现优先队列
heap = []
heapq.heappush(heap, 3) # 插入元素(O(log n))
heapq.heappush(heap, 1) # 堆调整 → [1,3]
min_val = heapq.heappop(heap) # 弹出最小元素(O(log n))
(2)集合(Set)
s1 = {1, 2, 3}
s2 = {3, 4, 5}
union = s1 | s2 # 并集 → {1,2,3,4,5}(O(len(s1)+len(s2)))
intersection = s1 & s2 # 交集 → {3}(O(min(len(s1), len(s2))))
七、应用场景与选择策略
1. 高频操作与数据结构选择
场景 | 推荐数据结构 | 原因 |
---|---|---|
快速键值查找 | 哈希表(字典) | O(1)平均查找时间复杂度 |
动态数据插入/删除 | 链表 | O(1)插入/删除(已知位置) |
数据排序与范围查询 | 平衡二叉搜索树(如AVL树) | O(log n)插入/删除/查询,有序遍历 |
任务调度(先进先出) | 队列 | FIFO特性符合调度顺序 |
2. 复杂度对比
数据结构 | 插入 | 删除 | 查找 | 空间 |
---|---|---|---|---|
数组(List) | O(n)(中间) | O(n)(中间) | O(1)(索引) | O(n)连续内存 |
链表 | O(1)(已知位置) | O(1)(已知位置) | O(n)(遍历) | O(n)分散内存 |
哈希表(Dict) | O(1)平均 | O(1)平均 | O(1)平均 | O(n) |
平衡树 | O(log n) | O(log n) | O(log n) | O(n) |
八、总结
-
三要素关系:
- 逻辑结构决定数据关系,存储结构影响性能,数据运算定义功能。
- 例如:队列的逻辑结构是“先进先出”,可用顺序存储(循环数组)或链式存储(链表)。
-
设计原则:
- 时间与空间权衡:哈希表用空间换时间,链表用时间换空间。
- 场景驱动选择:高频查询用哈希表,有序数据用树结构,动态数据用链表。
-
Python工具库:
- 列表(List)实现动态数组,字典(Dict)实现哈希表,
collections.deque
实现高效队列。
- 列表(List)实现动态数组,字典(Dict)实现哈希表,