数据结构 练习 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算法:参考 点击打开链接

原文地址:https://www.cnblogs.com/snake-hand/p/3187031.html