kruskal和prim算法如何实现最小生成树

kruskal和prim算法是用来求最小生成树的算法,那什么是最小生成树呢?
最小生成树是一副连通加权无向图中一棵权值最小的生成树,也就是图中包含全部节点且权值和最小的连通子图。

kruskal和prim算法讲解

对于kruskal和prim算法的讲解这里有个秒懂视频,讲解的很详细,可以参考下。
kruskal和prim算法秒懂视频

kruskal算法实现

步骤:

  1. 将图中的所有边取出并且按权值由小到大排序
  2. 将已排好序的边从小到大依次还原,若还原的过程中出现环,则舍弃该边
  3. 重复步骤2直到选出N-1条边为止
// 针对的对象:无向连通图
// 返回最小连通图的路径值和
const int MAX_E = 8;
const int MAX_V = 6;
struct edge { int u, v, cost; }; // 表示边e=(u, v), 权值为cost
edge es[MAX_E];
bool cmp(const edge& e1, const edge& e2)
{
	return e1.cost < e2.cost;
}

int kruskal()
{
	sort(es, es + MAX_E, cmp); // 按照edge.cost的顺序从小到大排列
	UF uf(MAX_V);  // 实例化并查集
	int res = 0;
	for (int i = 0; i < MAX_E; i++) // 如果已经加入n-1条边了就可以退出了
	{
		edge e = es[i];
		if (!uf.connected(e.u, e.v)) // 判断u和v是否在同一连通块,如果连通的话该边的加入就会导致出现环
		{
			uf.unioned(e.u, e.v); // 连接u和v
			res += e.cost;
		}
	}
	return res;
}

算法本质:贪心算法
适用类型:稀疏图(对边的操作较多)
时间复杂度:O(NlogN)

prim算法实现

步骤:

  1. 选取一个开始顶点,将图分为包含该顶点的选择区域和除该顶点外的未选择区域
  2. 在连接选择区域未选择区域的边中选取权值最小的边,并将该边中顶点没有在未选择区域中的点加入到选择区域点集中
  3. 重复步骤2直到所有的点都加入到选择区域
const int MAX_V = 6;
int cost[MAX_V][MAX_V] = {
		{0,4,2,INT_MAX,INT_MAX,INT_MAX},
		{4,0,1,3,INT_MAX,INT_MAX},
		{2,1,0,5,1,INT_MAX},
		{INT_MAX,3,5,0,2,1},
		{INT_MAX,INT_MAX,1,2,0,INT_MAX},
		{INT_MAX,INT_MAX,INT_MAX,1,INT_MAX,INT_MAX}
}; // cost[u][v]表示边e=(u,v)的权值(不存在的情况下设为INF )

int mincost[MAX_V]; // 保存连接两个区域的边的最小权值
int parent[MAX_V];	// 节点i的父节点
bool vis[MAX_V];	// 顶点i是否包含在集合中

int prim(int s = 0)
{
	// 初始化
	for (int i = 0; i < MAX_V; i++)
	{
		mincost[i] = INT_MAX;
		vis[i] = false;
	}
	mincost[s] = 0;
	vis[s] = true;
	int sumcost = 0;

	int v = s; // 表示新加入的结点,注意:后面导致mincost和parent更新的原因就是因为新节点v的加入
	while (true)
	{
		// 1. 更新连接两个区域边的信息(update)
		for (int i = 0; i < MAX_V; i++)
		{
			if (!vis[i] && cost[v][i] < mincost[i])
			{
				mincost[i] = cost[v][i]; // 更新连接两个区域的边的最小权值
				parent[i] = v;	// 更新父节点
			}
		}
		// 2. 找连接两个区域的最小权边上的没有访问的顶点(scan)
		v = -1;
		for (int i = 0; i < MAX_V; i++)
		{
			if (!vis[i] && (v == -1 || mincost[v] > mincost[i])) v = i;
		}
		if (v == -1) break; // 所有的节点被访问
		// 3. 添加节点到集合(add)
		vis[v] = true;
		sumcost += mincost[v];
	}
	return sumcost;
}

算法本质:动态规划算法
适用类型:稠密疏图(对顶点的操作较多)
时间复杂度:O(N^2)
该算法还可以用堆优化,时间复杂度为O(NlogN)

你可能感兴趣的:(算法)