一、栈(Stack)
定义
栈是一种**后进先出(LIFO,Last In First Out)**的数据结构。插入和删除操作只能在栈顶进行。
特点
- 只能从栈顶操作数据。
- 操作简单,时间复杂度为 O ( 1 ) O(1) O(1)。
应用场景
- 表达式求值(如括号匹配)。
- 深度优先搜索(DFS)。
时间复杂度
操作 | 时间复杂度 |
---|---|
入栈(push) | O ( 1 ) O(1) O(1) |
出栈(pop) | O ( 1 ) O(1) O(1) |
访问栈顶元素 | O ( 1 ) O(1) O(1) |
案例:括号匹配
问题描述:给定一个只包含 (
和 )
的字符串,判断括号是否匹配。
C++实现:
#include <iostream>
#include <stack>
using namespace std;
bool isValid(string s) {
stack<char> stk;
for (char c : s) {
if (c == '(') {
stk.push(c);
} else {
if (stk.empty() || stk.top() != '(') {
return false;
}
stk.pop();
}
}
return stk.empty();
}
int main() {
string s = "(())";
cout << (isValid(s) ? "Valid" : "Invalid") << endl;
return 0;
}
Python实现:
def is_valid(s):
stack = []
for c in s:
if c == '(':
stack.append(c)
else:
if not stack or stack[-1] != '(':
return False
stack.pop()
return len(stack) == 0
s = "(())"
print("Valid" if is_valid(s) else "Invalid")
Java实现:
import java.util.Stack;
public class Main {
public static boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
for (char c : s.toCharArray()) {
if (c == '(') {
stack.push(c);
} else {
if (stack.isEmpty() || stack.peek() != '(') {
return false;
}
stack.pop();
}
}
return stack.isEmpty();
}
public static void main(String[] args) {
String s = "(())";
System.out.println(isValid(s) ? "Valid" : "Invalid");
}
}
二、队列(Queue)
定义
队列是一种**先进先出(FIFO,First In First Out)**的数据结构,插入操作在队尾,删除操作在队首。
特点
- 操作受限。
- 时间复杂度为 O ( 1 ) O(1) O(1)。
应用场景
- 任务调度。
- 宽度优先搜索(BFS)。
时间复杂度
操作 | 时间复杂度 |
---|---|
入队 | O ( 1 ) O(1) O(1) |
出队 | O ( 1 ) O(1) O(1) |
案例:二叉树的层序遍历
问题描述:按层序输出二叉树的节点值。
C++实现:
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {
}
};
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
if (!root) return result;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
int size = q.size();
vector<int> level;
for (int i = 0; i < size; ++i) {
TreeNode* node = q.front(); q.pop();
level.push_back(node->val);
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
result.push_back(level);
}
return result;
}
int main() {
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
vector<vector<int>> result = levelOrder(root);
for (const auto& level : result) {
for (int val : level) {
cout << val << " ";
}
cout << endl;
}
return 0;
}
Python实现:
from collections import deque
def level_order(root):
if not root:
return []
result, queue = [], deque([root])
while queue:
level = []
for _ in range(len(queue)):
node = queue.popleft()
level.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
result.append(level)
return result
# TreeNode class definition
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
print(level_order(root))
Java实现:
import java.util.*;
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x; }
}
public class Main {
public static List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
List<Integer> level = new ArrayList<>();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
level.add(node.val);
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
result.add(level);
}
return result;
}
public static void main(String[] args) {
TreeNode root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
System.out.println(levelOrder(root));
}
}
三、堆(Heap)
定义
堆是一种基于树的数据结构,分为最大堆和最小堆:
- 最大堆:根节点值大于给定树中所有子节点的值。
- 最小堆:根节点值小于给定树中所有子节点的值。
通常使用堆实现一些需要自动索引的场景,如优先队列。
特点
- 深度为 ⌊ log n ⌋ \lfloor \log n \rfloor ⌊logn⌋,操作时间复杂度为 O ( log n ) O(\log n) O(logn)。
- 通常用数组表示,父节点、左子节点和右子节点与索引关系为:
- 父节点: parent ( i ) = ⌊ ( i − 1 ) / 2 ⌋ \text{parent}(i) = \lfloor (i-1)/2 \rfloor parent(i)=⌊(i−1)/2⌋
- 左子节点: left ( i ) = 2 i + 1 \text{left}(i) = 2i + 1 left(i)=2i+1
- 右子节点: right ( i ) = 2 i + 2 \text{right}(i) = 2i + 2 right(i)=2i+2
应用场景
- 优先队列(Priority Queue)
- 最大/最小 K 问题
时间复杂度
操作 | 时间复杂度 |
---|---|
插入(insert) | O ( log n ) O(\log n) O(logn) |
删除(delete) | O ( log n ) O(\log n) O(logn) |
取最大/最小值 | O ( 1 ) O(1) O(1) |
案例:前 K 个最大元素
问题描述:给定一个数组,找到其中前 K 个最大元素。
C++实现:
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
vector<int> topKElements(vector<int>& nums, int k) {
priority_queue<int, vector<int>, greater<int>> minHeap;
for (int num : nums) {
minHeap.push(num);
if (minHeap.size() > k) {
minHeap.pop();
}
}
vector<int> result;
while (!minHeap.empty()) {
result.push_back(minHeap.top());
minHeap.pop();
}
return result;
}
int main() {
vector<int> nums = {
3, 2, 1, 5, 6, 4};
int k = 2;
vector<int> result = topKElements(nums, k);
for (int val : result) {
cout << val << " ";
}
cout << endl;
return 0;
}
Python实现:
import heapq
def top_k_elements(nums, k):
return heapq.nlargest(k, nums)
nums = [3, 2, 1, 5, 6, 4]
k = 2
print(top_k_elements(nums, k))
Java实现:
import java.util.*;
public class Main {
public static List<Integer> topKElements(int[] nums, int k) {
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
for (int num : nums) {
minHeap.offer(num);
if (minHeap.size() > k) {
minHeap.poll();
}
}
List<Integer> result = new ArrayList<>(minHeap);
Collections.sort(result, Collections.reverseOrder());
return result;
}
public static void main(String[] args) {
int[] nums = {
3, 2, 1, 5, 6, 4};
int k = 2;
System.out.println(topKElements(nums, k));
}
}
下面是并查集和树状数组的内容,整合到现有文档中:
四、并查集(Union-Find)
定义
并查集是一种用于处理动态连通性问题的数据结构,主要支持以下两种操作:
- **合并:将两个元素所在的集合合并。
- 查找:查询某个元素属于哪个集合。
特点
- 常用于解决连通性问题(如网络连通、图的连通分量)。
- 通过路径压缩和按秩合并优化,时间复杂度接近 O ( 1 ) O(1) O(1)。
应用场景
- 判断无向图是否有环。
- 网络连通性问题。
- 最小生成树(Kruskal算法)。
时间复杂度
操作 | 时间复杂度 |
---|---|
查找 | O ( l o g ( n ) ) O(log(n)) O(log(n)) |
合并 | O ( l o g ( n ) ) O(log(n)) O(log(n)) |
案例:判断图是否连通
问题描述:给定包含 n
个节点的无向图,以及一些边,判断图是否是连通的。
C++实现:
#include <iostream>
#include <vector>
using namespace std;
class UnionFind {
public:
UnionFind(int n) : parent(n), rank(n, 1) {
for (int i = 0; i < n; ++i) parent[i] = i;
}
int find(int x) {
if (x != parent[x]) {
parent[x] = find(parent[x]); // 路径压缩
}
return parent[x];
}
void unionSet(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
if (rank[rootX] > rank[rootY]) {
parent[rootY] = rootX;
} else if (rank[rootX] < rank[rootY]) {
parent[rootX] = rootY;
} else {
parent[rootY] = rootX;
rank[rootX]++;
}
}
}
private:
vector<int> parent, rank;
};
int main() {
UnionFind uf(5);
uf.unionSet(0, 1);
uf.unionSet(1, 2);
cout << (uf.find(0) == uf.find(2) ? "Connected" : "Not Connected") << endl;
return 0;
}
Python实现:
class UnionFind:
def __init__(self, n):
self.parent = list(range(n))
self.rank = [1] * n
def find(self, x):
if x != self.parent[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:
if self.rank[rootX] > self.rank[rootY]:
self.parent[rootY] = rootX
elif self.rank[rootX] < self.rank[rootY]:
self.parent[rootX] = rootY
else:
self.parent[rootY] = rootX
self.rank[rootX] += 1
uf = UnionFind(5)
uf.union(0, 1)
uf.union(1, 2)
print("Connected" if uf.find(0) == uf.find(2) else "Not Connected")
Java实现:
class UnionFind {
private int[] parent;
private int[] rank;
public UnionFind(int n) {
parent = new int[n];
rank = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
rank[i] = 1;
}
}
public int find(int x) {
if (x != parent[x]) {
parent[x] = find(parent[x]); // 路径压缩
}
return parent[x];
}
public void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
if (rank[rootX] > rank[rootY]) {
parent[rootY] = rootX;
} else if (rank[rootX] < rank[rootY]) {
parent[rootX] = rootY;
} else {
parent[rootY] = rootX;
rank[rootX]++;
}
}
}
}
public class Main {
public static void main(String[] args) {
UnionFind uf = new UnionFind(5);
uf.union(0, 1);
uf.union(1, 2);
System.out.println(uf.find(0) == uf.find(2) ? "Connected" : "Not Connected");
}
}
五、树状数组(Fenwick Tree)
定义
树状数组是一种用于高效维护数组前缀和的数据结构,支持快速更新和查询操作。
特点
- 时间复杂度为 O ( log n ) O(\log n) O(logn)。
- 适用于动态数组。
应用场景
- 区间查询和更新。
- 逆序对计数。
时间复杂度
操作 | 时间复杂度 |
---|---|
单点更新 | O ( log n ) O(\log n) O(logn) |
前缀查询 | O ( log n ) O(\log n) O(logn) |
案例:计算数组前缀和
问题描述:支持动态更新和快速前缀和查询。
C++实现:
#include <iostream>
#include <vector>
using namespace std;
class FenwickTree {
public:
FenwickTree(int n) : tree(n + 1, 0) {
}
void update(int i, int delta) {
while (i < tree.size()) {
tree[i] += delta;
i += i & -i;
}
}
int query(int i) {
int sum = 0;
while (i > 0) {
sum += tree[i];
i -= i & -i;
}
return sum;
}
private:
vector<int> tree;
};
int main() {
FenwickTree ft(5);
ft.update(1, 5);
ft.update(2, 3);
cout << ft.query(2) << endl; // 输出8
return 0;
}
Python实现:
class FenwickTree:
def __init__(self, n):
self.tree = [0] * (n + 1)
def update(self, i, delta):
while i < len(self.tree):
self.tree[i] += delta
i += i & -i
def query(self, i):
sum_ = 0
while i > 0:
sum_ += self.tree[i]
i -= i & -i
return sum_
ft = FenwickTree(5)
ft.update(1, 5)
ft.update(2, 3)
print(ft.query(2)) # 输出8
Java实现:
class FenwickTree {
private int[] tree;
public FenwickTree(int n) {
tree = new int[n + 1];
}
public void update(int i, int delta) {
while (i < tree.length) {
tree[i] += delta;
i += i & -i;
}
}
public int query(int i) {
int sum = 0;
while (i > 0) {
sum += tree[i];
i -= i & -i;
}
return sum;
}
public static void main(String[] args) {
FenwickTree ft = new FenwickTree(5);
ft.update(1, 5);
ft.update(2, 3);
System.out.println(ft.query(2)); // 输出8
}
}