C++算法实例
以下是一些难度中等的C++算法实例,涵盖常见数据结构、经典算法及实际问题解决场景,每个示例均附简要说明。
二分查找
int binarySearch(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) return mid;
else if (nums[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
在有序数组中高效查找目标值,时间复杂度为O(log n)。
快速排序
void quickSort(vector<int>& arr, int low, int high) {
if (low < high) {
int pivot = partition(arr, low, high);
quickSort(arr, low, pivot - 1);
quickSort(arr, pivot + 1, high);
}
}
int partition(vector<int>& arr, int low, int high) {
int pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] < pivot) swap(arr[++i], arr[j]);
}
swap(arr[i + 1], arr[high]);
return i + 1;
}
分治思想实现排序,平均时间复杂度O(n log n)。
链表反转
ListNode* reverseList(ListNode* head) {
ListNode *prev = nullptr, *curr = head;
while (curr) {
ListNode* next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
return prev;
}
通过迭代修改指针方向实现链表反转。
动态规划:斐波那契数列
int fib(int n) {
if (n <= 1) return n;
vector<int> dp(n + 1);
dp[0] = 0; dp[1] = 1;
for (int i = 2; i <= n; i++)
dp[i] = dp[i - 1] + dp[i - 2];
return dp[n];
}
使用动态规划避免递归的重复计算。
Dijkstra最短路径算法
void dijkstra(vector<vector<pair<int, int>>>& graph, int start) {
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
vector<int> dist(graph.size(), INT_MAX);
dist[start] = 0;
pq.emplace(0, start);
while (!pq.empty()) {
auto [d, u] = pq.top(); pq.pop();
if (d > dist[u]) continue;
for (auto& [v, w] : graph[u]) {
if (dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
pq.emplace(dist[v], v);
}
}
}
}
基于优先队列实现带权图单源最短路径查找。
二叉树层序遍历
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
queue<TreeNode*> q;
if (root) q.push(root);
while (!q.empty()) {
int size = q.size();
vector<int> level;
while (size--) {
auto node = q.front(); q.pop();
level.push_back(node->val);
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
res.push_back(level);
}
return res;
}
使用队列实现二叉树的广度优先遍历。
检测有向无环图依赖关系的C++实现
检测有向无环图依赖关系的C++实现
检测有向无环图(DAG)依赖关系的常见方法是拓扑排序。以下是一个完整的C++实现示例,包含图的构建、拓扑排序和依赖关系检测。
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
class Graph {
int V;
vector<vector<int>> adj;
public:
Graph(int V) : V(V), adj(V) {}
void addEdge(int u, int v) {
adj[u].push_back(v);
}
vector<int> topologicalSort() {
vector<int> inDegree(V, 0);
for (int u = 0; u < V; ++u) {
for (int v : adj[u]) {
inDegree[v]++;
}
}
queue<int> q;
for (int u = 0; u < V; ++u) {
if (inDegree[u] == 0) {
q.push(u);
}
}
vector<int> result;
while (!q.empty()) {
int u = q.front();
q.pop();
result.push_back(u);
for (int v : adj[u]) {
if (--inDegree[v] == 0) {
q.push(v);
}
}
}
if (result.size() != V) {
return {}; // 存在环
}
return result;
}
bool hasCycle() {
return topologicalSort().empty();
}
void printDependencies() {
auto order = topologicalSort();
if (order.empty()) {
cout << "Graph contains a cycle!" << endl;
return;
}
cout << "Dependency order: ";
for (int u : order) {
cout << u << " ";
}
cout << endl;
cout << "Detailed dependencies:" << endl;
for (int u : order) {
if (!adj[u].empty()) {
cout << u << " depends on: ";
for (int v : adj[u]) {
cout << v << " ";
}
cout << endl;
}
}
}
};
DAG依赖关系测试用例
以下是30个不同结构的DAG测试用例,可用于验证上述实现:
- 简单线性依赖
Graph g1(3);
g1.addEdge(0, 1);
g1.addEdge(1, 2);
g1.printDependencies();
- 多分支无交叉
Graph g2(4);
g2.addEdge(0, 1);
g2.addEdge(0, 2);
g2.addEdge(1, 3);
g2.printDependencies();
- 多分支有交叉
Graph g3(5);
g3.addEdge(0, 1);
g3.addEdge(0, 2);
g3.addEdge(1, 3);
g3.addEdge(2, 3);
g3.addEdge(3, 4);
g3.printDependencies();
- 多入口点
Graph g4(6);
g4.addEdge(0, 2);
g4.addEdge(1, 2);
g4.addEdge(2, 3);
g4.addEdge(3, 4);
g4.addEdge(3, 5);
g4.printDependencies();
- 复杂依赖网
Graph g5(7);
g5.addEdge(0, 1);
g5.addEdge(0, 2);
g5.addEdge(1, 3);
g5.addEdge(2, 3);
g5.addEdge(3, 4);
g5.addEdge(3, 5);
g5.addEdge(4, 6);
g5.addEdge(5, 6);
g5.printDependencies();
6-30. 其他测试用例模式(可根据需要扩展):
- 星型依赖结构
- 树形依赖结构
- 网格状依赖
- 分层依赖结构
- 随机生成的有效DAG
- 包含孤立节点的图
- 所有节点相互独立的图
- 单节点自环(应检测为环)
- 简单环(两个节点互依赖)
- 复杂环结构
环检测验证
以下是一些包含环的测试用例,用于验证环检测功能:
// 简单环
Graph cycle1(2);
cycle1.addEdge(0, 1);
cycle1.addEdge(1, 0);
cycle1.printDependencies();
// 大环
Graph cycle2(5);
cycle2.addEdge(0, 1);
cycle2.addEdge(1, 2);
cycle2.addEdge(2, 3);
cycle2.addEdge(3, 4);
cycle2.addEdge(4, 0);
cycle2.printDependencies();
// 局部环
Graph cycle3(6);
cycle3.addEdge(0, 1);
cycle3.addEdge(1, 2);
cycle3.addEdge(2, 3);
cycle3.addEdge(3, 1); // 形成局部环
cycle3.addEdge(2, 4);
cycle3.addEdge(4, 5);
cycle3.printDependencies();
实际应用示例
构建任务调度系统依赖关系检测:
Graph taskGraph(8);
// 任务0: 无依赖
taskGraph.addEdge(1, 0); // 任务1依赖任务0
taskGraph.addEdge(2, 0);
taskGraph.addEdge(3, 1);
taskGraph.addEdge(3, 2);
taskGraph.addEdge(4, 3);
taskGraph.addEdge(5, 3);
taskGraph.addEdge(6, 4);
taskGraph.addEdge(6, 5);
taskGraph.addEdge(7, 6);
taskGraph.printDependencies();
性能优化建议
对于大规模图,可以考虑以下优化:
- 使用邻接表存储图结构
- 实现并行拓扑排序算法
- 使用更高效的数据结构如Fibonacci堆
- 对静态图进行预处理
可视化建议
为了更好地理解依赖关系,可以:
- 将拓扑排序结果图形化展示
- 使用Graphviz生成DOT格式的依赖图
- 实现不同颜色标记关键路径
- 高亮显示循环依赖(如果存在)
以上实现和测试用例涵盖了DAG依赖关系检测的主要场景,可根据具体需求进行调整和扩展。
KMP算法
KMP算法简介
KMP算法(Knuth-Morris-Pratt)是一种高效的字符串匹配算法,通过预处理模式串生成部分匹配表(next
数组),避免主串回溯,将时间复杂度优化至O(n+m)。
核心实现步骤
1. 构建next数组
next
数组记录模式串前缀与后缀的最长公共长度,用于匹配失败时快速跳转。
vector<int> buildNext(const string& pattern) {
vector<int> next(pattern.size(), 0);
int j = 0;
for (int i = 1; i < pattern.size(); ) {
if (pattern[i] == pattern[j]) {
next[i++] = ++j;
} else {
if (j != 0) j = next[j-1];
else next[i++] = 0;
}
}
return next;
}
2. 匹配过程
利用next
数组跳过不必要的比较:
int kmpSearch(const string& text, const string& pattern) {
vector<int> next = buildNext(pattern);
int i = 0, j = 0;
while (i < text.size() && j < pattern.size()) {
if (text[i] == pattern[j]) {