数据结构 练习 22-并查集以及图的最小生成树
前言
本博客主要介绍并查集以及图的最小生成树。对于并查集,我们引入其基本概念,并分析其复杂度,最后利用并查集来分析最小生成树。
并查集
参考文献《算法导论》,博客 http://blog.csdn.net/dm_vincent/article/details/7655764。
并查集包括三个操作:make_set,find_set,union_set。
链表表示:
每个节点包括一个value,两个指针:一个指向下一个节点,一个指向头节点,还包括一个head和一个tail;
每一个集合的代表为头结点,所以每个节点都得指向头结点,这样能迅速定位头结点。
复杂度如下
树根表示:
树根表示,可以引入两种优化,按秩合并,路径压缩,当同时使用这优化时,最坏情况运行时间为:O(m*α(n)),m是总的操作次数,α(n)是一个增长及其缓慢的函数,通常α(n)<=4;所以最坏情况的复杂度可以看做是线性的;
图的最小生成树
图作为一种复杂的数据结构,前面 简单学习了图的遍历,接下来简单介绍最小生成树。
相关概念:
连通图: 对于无向图,任何两个顶点,他们之间都存在一条路径,则该无向图为连通图;
强连通图:对于有向图,图中任意两个顶点之间都存在一条有向路径,则该有向图为强连通图;
连通分量:非连通图中的各个连通子图成为该图的连通分量。
解决最小生成树的方法,用到的思想贪心,并查集,递归。
kruskal+并查集实现:
#include <iostream> #include <string> #include <cmath> #include <algorithm> #define BUG puts("here!!!"); using namespace std; const int N = 5005; int pre[N];//空间复杂度 int n, m; struct Node { int u, v; int w; } e[N]; bool cmp(const Node a, const Node b) { return a.w < b.w; } void makeSet(int n) { for(int i = 0; i <= n; i++) { pre[i] = i; } } int findSet(int a) { if(pre[a] == a) return a; return pre[a] = findSet(pre[a]); } void kruskal() { int fu, fv, sum = 0,count = 0; sort(e, e+m, cmp); makeSet(n); for(int i = 0; i < m; i++) { fu = findSet(e[i].u); fv = findSet(e[i].v); if(fu != fv) { sum += e[i].w; count++; if(count == n-1) break; pre[fv] = fu; } } cout << sum << endl; } int main() { while(cin >> n, n) { cin >> m; for(int i = 0; i < m; i++) { cin >> e[i].u >> e[i].v >> e[i].w; } kruskal(); } }
kruskal是基于边的查找,先得对边排序,每次都查看当前最优,贪心的思想。
prim算法:参考 点击打开链接