本博客就蓝桥杯中所需的数据结构基础知识进行解释,包括:链表、栈、队列、二叉树、堆和哈希表。每一种数据结构都在给出概念解释的同时,给出了其定义方式和基本操作的示例代码,以供低年级师弟师妹们学习和练习。
前序知识:
(1)Python基础语法
(2)Python OOP(面向对象编程)
一、链表
1. 定义:
链表是由节点构成的线性数据结构,每个节点包含数据域(Data)和指针域(Next)。如下图所示为典型的“单链表”,节点通过指针连接形成链式结构,支持动态内存分配。
2. 核心知识点:
(1)节点结构:数据域存储值,指针域存储下一个节点的地址。
(2)单链表 vs 双链表:双链表多一个指向前驱节点的指针。下图为“ 双链表”,比较二者的差异:
(3)操作时间复杂度:
- 访问:O(n) ;
- 插入/删除:O(1)(已知位置时)。
(4)虚拟头节点:简化边界条件处理。
(5)优点:数组需要连续空间存储,而链表则可以是非连续空间存储,使用Next指针连接下一个节点,提升了存储资源利用率。
3. 示例代码:
# 链表
class Node:
def __init__(self, data):
self.data = data # 节点数据
self.next = None # 下一个节点指针
# 创建链表
head = Node(1) # 头节点
second = Node(2)
third = Node(3)
head.next = second # 连接节点
second.next = third
# 遍历链表
def print_list(node):
while node is not None:
print(node.data, end=" -> ")
node = node.next
print("None")
print_list(head) # 输出:1 -> 2 -> 3 -> None
# 插入节点(在第二个位置插入0)
new_node = Node(0)
new_node.next = second.next
second.next = new_node
print_list(head) # 输出:1 -> 2 -> 0 -> 3 -> None
# 删除节点(删除值为2的节点)
current = head
while current.next.data != 2:
current = current.next
current.next = current.next.next
print_list(head) # 输出:1 -> 0 -> 3 -> None
二、栈
1. 定义:
后进先出(LIFO)的线性数据结构,只允许在栈顶进行插入(push)和删除(pop)操作。
2. 核心知识点:
(1)核心操作:
- push:元素入栈;
- pop:栈顶元素出栈;
- peek:查看栈顶元素。
(2)实现方式:数组/链表。
(3)经典应用:
- 函数调用栈;
- 括号匹配校验。
3. 示例代码:
# 用列表模拟栈,也可以用链表来模拟栈
stack = []
# 入栈操作
stack.append(10) # 栈底 -> [10]
stack.append(20) # 栈变为 [10, 20]
stack.append(30) # 栈顶 -> [10, 20, 30]
# 查看栈顶(不弹出)
print("栈顶元素:", stack[-1]) # 输出30
# 出栈操作
top = stack.pop() # 弹出30,栈变为 [10, 20]
print(f"弹出元素: {top}")
# 判断栈是否为空
is_empty = len(stack) == 0 # 当前栈不为空,返回False
三、队列
1. 定义:
先进先出(FIFO)的线性数据结构,元素从队尾入队(enqueue),从队首出队(dequeue)。
2. 核心知识点:
(1)核心操作:
- enqueue:元素加入队尾;
- dequeue:移除队首元素。
(2)循环队列:解决假溢出问题。
(3)优先队列:元素带有优先级。
3. 示例代码:
# 队列
# 定义队列节点类
class QueueNode:
def __init__(self, value):
self.value = value # 节点存储的值
self.next = None # 指向下一个节点的指针
# 手动实现队列类
class MyQueue:
def __init__(self):
self.head = None # 队首指针(链表头)
self.tail = None # 队尾指针(链表尾)
self.size = 0 # 队列长度
def enqueue(self, value):
""" 入队操作:在队尾添加元素 """
new_node = QueueNode(value) # 创建新节点
if self.tail is None: # 如果队列为空
self.head = new_node # 队首和队尾都指向新节点
self.tail = new_node
else:
self.tail.next = new_node # 当前队尾节点的next指向新节点
self.tail = new_node # 更新队尾指针
self.size += 1
def dequeue(self):
""" 出队操作:移除并返回队首元素 """
if self.is_empty():
raise IndexError("队列为空,无法出队") # 处理空队列异常
value = self.head.value # 保存队首值
self.head = self.head.next # 队首指针后移
if self.head is None: # 如果队列已空
self.tail = None # 同时清空队尾指针
self.size -= 1
return value
def peek(self):
""" 查看队首元素(不删除) """
if self.is_empty():
return None
return self.head.value
def is_empty(self):
""" 判断队列是否为空 """
return self.size == 0
# 测试队列操作
q = MyQueue()
# 入队测试
q.enqueue("A") # 队列:A
q.enqueue("B") # 队列:A -> B
q.enqueue("C") # 队列:A -> B -> C
print("当前队首:", q.peek()) # 输出 A
# 出队测试
print("出队元素:", q.dequeue()) # 移除A,队列变为 B -> C
print("新队首:", q.peek()) # 输出 B
# 空队列测试
q.dequeue() # 移除B
q.dequeue() # 移除C
print("队列是否为空:", q.is_empty()) # 输出 True
四、二叉树
1. 定义:
“二叉”也就是只有两个枝丫,每个节点最多有两个子节点的树形结构,包含根节点、左子树和右子树。如下图,左侧是一般的“树”结构,右侧是“二叉树”。
2. 核心知识点:
(1)遍历方式:
- 前序:根->左->右;
- 中序:左->根->右(BST有序遍历);
- 后序:左->右->根。
(2)二叉树类型:
- 完全二叉树,满足:
①除最后一层外,其他层的节点数必须达到最大值(即每层都被填满);
②最后一层的节点必须从左到右连续填充,不能有空隙。
- 二叉搜索树(BST),是一种具有排序性质的二叉树,满足:
①左子树所有节点的值 < 根节点的值;
②右子树所有节点的值 > 根节点的值;
③左右子树也必须是二叉搜索树。
3. 示例代码:
# 二叉树
class TreeNode:
def __init__(self, val=0):
self.val = val # 节点值
self.left = None # 左子节点
self.right = None # 右子节点
# 构建二叉树
# 1
# / \
# 2 3
# /
# 4
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
# 中序遍历函数
def inorder_traversal(node):
if node: # 节点存在时递归
inorder_traversal(node.left) # 先遍历左子树
print(node.val, end=" ") # 访问当前节点
inorder_traversal(node.right) # 最后遍历右子树
inorder_traversal(root) # 输出:4 2 1 3
五、堆
1. 定义:
完全二叉树实现的优先队列,满足父节点值总大于/小于子节点值(大根堆/小根堆)。
2. 核心知识点:
(1)堆性质:
- 小根堆:父节点 ≤ 子节点;
- 大根堆:父节点 ≥ 子节点。
(2)堆化(Heapify):调整树结构维持堆特性。
(3)典型应用:Top K问题,堆排序。
3. 示例代码:
# 堆
import heapq # Python内置堆模块(默认最小堆)
# 创建堆
heap = []
heapq.heappush(heap, 5) # 堆结构:5
heapq.heappush(heap, 2) # 堆结构:2-5
heapq.heappush(heap, 8) # 堆结构:2-5-8
# 查看堆顶元素
print("堆顶元素:", heap[0]) # 输出2
# 弹出最小元素
min_val = heapq.heappop(heap) # 弹出2,堆变为 [5,8]
print(f"弹出最小值: {min_val}")
# 列表转堆(原地转换)
nums = [9, 3, 7, 1]
heapq.heapify(nums) # 堆结构变为 [1,3,7,9]
六、哈希表
1. 定义:
通过哈希函数将键映射到存储位置的键值对数据结构,支持快速查找。
2. 核心知识点:
(1)哈希函数:均匀分布减少冲突。
(2)冲突解决:
- 开放寻址法;
- 链地址法(常用)。
(3)时间复杂度:平均O(1)查找。
3. 示例代码:
# 哈希表
# 使用字典实现
student_scores = {}
student_scores["Alice"] = 95 # 插入键值对
student_scores["Bob"] = 88
# 查询操作
print("Alice的成绩:", student_scores.get("Alice", -1)) # 输出95
# 处理冲突的哈希表实现
class MyHashTable:
def __init__(self, size=10):
self.size = size
self.buckets = [[] for _ in range(size)] # 创建空桶数组
def _hash(self, key):
return hash(key) % self.size # 简单哈希函数
def insert(self, key, value):
index = self._hash(key)
bucket = self.buckets[index]
for i, (k, v) in enumerate(bucket): # 遍历桶内元素
if k == key: # 键已存在则更新值
bucket[i] = (key, value)
return
bucket.append((key, value)) # 添加新键值对
def get(self, key):
index = self._hash(key)
bucket = self.buckets[index]
for k, v in bucket:
if k == key:
return v
return None # 未找到返回None
# 测试自定义哈希表
ht = MyHashTable()
ht.insert("apple", 5)
ht.insert("banana", 7)
print("apple数量:", ht.get("apple")) # 输出5