最短路径、最小生成树、二叉树实现
最短路径
单源最短路:已知起点,求到达其它点的最短路径
常用:Dijkstra算法、Bellman-Ford算法、SPFA算法
多源最短路:求任意两点之间的最短路径
常用:Floyd算法
上述算法介绍,推荐文章:http://t.csdnimg.cn/IuCsu
Dijkstra(迪杰斯特拉算法)
源码示例:
int n; // 顶点索引从 1 - n
int g[N][N], dis[N], vis[N];
void Dij (int pre) { // pre 表示源点索引
memset(dis, 0x3f, sizeof dis); // dis[i] 表示从源点到 i 点的距离
memset(vis, 0, sizeof vis);
dis[pre] = 0;
for (int i = 0; i < n; i++) {
int u = -1;
// 找到 dis 数组中最小距离的索引
for (int j = 1; j <= n; j++) {
if ((!vis[j]) && (u == -1 || dis[j] < dis[u])) u = j;
}
vis[u] = 1;
// 更新 dis 数组
for (int j = 1; j <= n; j++) {
if (!vis[j] && dis[j] > dis[u] + g[u][j]) {
dis[j] = dis[u] + g[u][j];
}
}
}
}
Floyd(弗洛伊德算法)
源码示例:
int n; // 顶点索引从 1 - n
int g[N][N];
void floyd() {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
g[i][j] = INF;
}
g[i][i] = 0;
}
/*
输入邻接矩阵 g
*/
for (int k = 1; k <= n; k++) { // 枚举中间点,即一定经过 k 点
for (int i = 1; i <= n; i++) { // 枚举起点
for (int j = 1; j <= n; j++) { // 枚举终点
g[i][j] = min(g[i][j], g[i][k] + g[k][j]); // 状态转移方程
}
}
}
// if (g[x][y] > INF / 2) cout << "impossible" << endl;
// else cout << g[x][y] << endl;
/*解释为什么不是">INF"而是“>INF/2”:由于题目中可能会有负数边存在,而在方程“dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]); ”中我们可以发现,如果边为负数居然会把INF更新为INF-x,但是这个值实际上并不是我们能到达的距离。根据题目中数据范围,我们可以发现,我们虽然不能写成”>INF",但是“>INF/2”是可以判断是否能到达终点的。*/
}
最小生成树
Kruskal(克鲁斯卡尔算法)
源码示例:
int n, m; // n 为顶点个数,m 为边数
int f[N];
struct node {
int x, y, w;
}a[N];
int find(int x) {
return x == f[x] ? x : f[x] = find(x);
}
bool cmp(node x, node y) {
return x.w < y.w;
}
sort(a + 1, a + 1 + n, cmp);
int ans = 0;
for (int i = 1; i <= m; i++) {
int xx = find(a[i].x);
int yy = find(a[i].y);
if (xx == yy) continue;
f[xx] = yy;
ans += a[i].w;
}
Prime
源码示例:
int n; // 顶点索引从 1 - n
int g[N][N], dis[N], vis[N];
int len = 0;
void Prime () {
memset(dis, 0x3f, sizeof dis); // dis[i] 表示从已访问节点到未访问节点 i 的距离
memset(vis, 0, sizeof vis);
dis[1] = 0;
for (int i = 0; i < n; i++) {
int u = -1, mi = INF;
// 找到 dis 数组中最小距离的索引
for (int j = 1; j <= n; j++) {
if (!vis[j] && dis[j] < mi) {
u = j;
mi = dis[j];
}
}
vis[u] = 1;
len += mi; // 计算最小生成树的总和
// 更新 dis 数组
for (int j = 1; j <= n; j++) {
if (!vis[j] && g[u][j] < dis[j]) {
dis[j] = g[u][j];
}
}
}
}
二叉树
基本性质
- 二叉树的第 i 层上最多有 2^(i - 1) 个结点
- 在一棵深度为 k 的二叉树中,最多有 (2^k - 1 )个结点,最少有 k 个结点
- 在一棵二叉树中,如果叶子结点的个数为 n0,度为 2 的结点个数为 n2,则 n0 = n2 + 1
- 具有 n 个结点的完全二叉树的深度为 floor(log2 (n)) + 1 // floor函数用于向下取整
- 对一颗具有 n 个结点的完全二叉树中的结点从 1 开始按层序编号,则对于任意编号 i 的结点,它的左孩子的结点编号为 2 * i,右孩子的节点编号为 2 * i + 1
第五点适用于数组和完全二叉树的转换,有些题目可以通过建立数组来代替建树,例如建立小顶堆和大顶堆
struct TreeNode {
char val;
TreeNode *l, *r;
};
建树
方法有很多,扩展先序遍历序列,前序+中序,后序+中序……
-
扩展先序遍历序列
TreeNode* Creat(TreeNode *t) { char ch; cin >> ch; if (ch == '#') t = nullptr; else { t = new TreeNode; t->val = ch; t->l = Creat(t->l); t->r = Creat(t->r); } } -
前序+中序
int mid[N], pre[N]; // 中序,前序 //此方法由长度确定终止条件 TreeNode* Creat(int midL, int preL, int len) { if (len == 0) return nullptr; TreeNode* p = new TreeNode; p->val = pre[preL]; p->l = p->r = nullptr; int k = 0; for (int i = midL; i < midL + len; i++) { if (mid[i] == pre[preL]){ k = i - midL; break; } } p->r = creat(midL, preL + 1, k); p->l = creat(midL + k + 1, preL + k + 1, len - k - 1); return p; } int mian() { TreeNode *p = Creat(1, 1, n); } -
后序+中序
int post[N], mid[N]l; // 后序,中序 // 此方法由左右子树是否存在确定终止条件 TreeNode* Creat(int postL, int postR, int midL, int midR) { if (postL > postR) return nullptr; TreeNode* p = new TreeNode; p->val = post[postR]; p->l = p->r = nullptr; int i; for (i = midL; i <= midR; i++) { if (mid[i] == post[postR]) break; } p->l = Creat(postL, postL + i - midL - 1, midL, i - 1); p->r = Creat(postL + i - midL, postR - 1, i + 1, midR); return p; }
遍历(除层序遍历外,建议使用递归)
-
前序遍历(中左右)
void PreOrder(TreeNode *t) { if (t == nullptr) return ; else { cout << t->val; PreOrder(t->l); PreOrder(t->r); } } -
中序遍历(左中右)
void InOrder(TreeNode *t) { if (t == nullptr) return ; else { InOrder(t->l); cout << t->val; InOrder(t->r); } } -
后序遍历(左右中)
void PostOrder(TreeNode *t) { if (t == nullptr) return ; else { PostOrder(t->l); PostOrder(t->r); cout << t->val; } } -
层序遍历
void LeverOrder(TreeNode *t) { queue<TreeNode*> qu; if (t == nullptr) return ; qu.push(t); while (!qu.empty()) { TreeNode tmp = qu.top(); qu.pop(); cout << tmp->val; if (tmp->l != nullptr) qu.push(tmp->l); if (tmp->r != nullptr) qu.push(tmp->r); } }

浙公网安备 33010602011771号