用Prim和Kruskal算法实现图的最小生成树

1.最小生成树的概念

  

最小生成树   由一个网络生成的各边的权数总和最小的生成树,记为MST(Minimum Cost Spanning Tree)。

MST性质   设N=(V,{E})是一个连通的网络,U是V的真子集,若边(u,v)[uÎU,vÎV-U]是E中所有一个端点在U内,一个端点不在U内的边中权值最小的一条边(轻边),则一定存在G的一棵生成树包括此边。


1.Prim算法:

•主:带权邻接矩阵G.arcs[n][n]—记录图
•辅:数组closedge[i](i=0..n-1)—记录候选边
–lowcost

    当前关联vi的轻边权值

–adjvex

    该边依附的U集合中的顶点下标

    示例初值:    0  1   2   3  4   5

     lowcost        0  6   1  5   µ  µ

      adjvex        0  0   0   0  0   0

算法步骤

1)初始化closedge[j](j=0..n-1)                              O(n)

2)重复n-1次以下操作:

  2.1)在closedge[j](j=0..n-1)中选择最小且非0的  lowcost,记录其j 值(设为k)和相应的adjvex;                 O(n2)

  2.2)输出该边(adjvex,k);                                  O(n)

  2.3)顶点k并入U集:closedge[k].lowcost=0; O(n)

  2.4)调整候选边集closedge[j](j=0..n-1):           O(n2)

   若G.arcs[k][j]< closedge[j].lowcost,

   则更改closedge[j]:adjvex=k,lowcost=G.arcs[k][j]

                                                                              O(n2)

C++代码

#include<iostream>
#include<stdlib.h>
using namespace std;
#define MAX 100
class block {
public:
	int lowcost;
	int adjvex;  //关联的顶点
};
class Graph {
public:
	char vertex_num[MAX];  //顶点信息对应的矩阵的编号
	int e[MAX][MAX];
	int vexnum;   //图的顶点数目
	int edgenum;  //图的边的数目     
};
void Prim(Graph G);
int findmin(block*, int);
int main()
{
	int i, j;
	//正确输入用关联矩阵来存储一个图,并且定义closeedge
	Graph G;
	cout<< "请输入无向图的顶点数目和图的边的数目\n";
	cin >> G.vexnum;
	cin >> G.edgenum;
//初始化关联矩阵
	for(i=1;i<=G.vexnum;i++)
		for (j = 1; j <= G.vexnum; j++)
		{
			if (i == j)
				G.e[i][j] = 0;
			else
				G.e[i][j] = 99999;
		}
	
	
	cout << "请输入各顶点的信息\n";

	for (i = 1; i <= G.vexnum; i++)
	{
		cin >> G.vertex_num[i];
	}
	cout << "请输入各边的相关信息\n";
	int j1,j2;
	char vert1, vert2;
	int weight;
	for (i = 1; i <= G.edgenum; i++)
	{
		cin >> vert1;
		cin >> vert2;
		cin >> weight;
		for (j1 = 1; G.vertex_num[j1] != vert1; j1++);
		for (j2 = 1; G.vertex_num[j2] != vert2; j2++);
		G.e[j1][j2] = weight;
		G.e[j2][j1] = weight;
	}
	/*//存储检查
	for (i = 1; i <= G.vexnum; i++)
	{
		for (j = 1; j <= G.vexnum; j++)
			cout << G.e[i][j] << " ";
		cout << "\n";
	}*/
	Prim(G);
	system("pause");

}
void Prim(Graph G)
{
	block closeedge[MAX];
	//先初始化closeedge数组,用e[][]的某一行(我选的是第一行)进行初始化
	//然后选取第一行中的最小权值连接的顶点,输出信息,加入到U集合中,(即将lowcost=0)
	//并且用该顶点去疏散其他还未进入U集合的点,如此往复
	int i, k, j;
	for (i = 1; i <= G.vexnum; i++)
	{
		closeedge[i].adjvex = 1;
		closeedge[i].lowcost = G.e[1][i];
	}
	cout << "从1号顶点开始\n";
	for (i = 2; i <= G.vexnum; i++)
	{
		k = findmin(closeedge,G.vexnum);
		closeedge[k].lowcost = 0; //加入U集合
		cout << "下一个顶点是" << G.vertex_num[k]<<" ";
			cout<<"对应的边的权值是" << G.e[k][closeedge[k].adjvex]<<"\n";
		for (j = 1; j <= G.vexnum; j++)
		{
			if (G.e[k][j] < closeedge[j].lowcost)
			{
				closeedge[j].lowcost = G.e[k][j];
				closeedge[j].adjvex = k;
			}
		}
	}
}
int findmin(block*close,int vexnum)
{
	int min = 1, lows = 99999;
	int i;
	for (i = 1; i <= vexnum; i++)
	{
		if (close[i].lowcost < lows&&close[i].lowcost != 0)
		{
			lows = close[i].lowcost;
			min = i;
		}
	}
	return min;

}

2.Kruskal算法

1)初始化T:顶点集=所有顶点,每个独立的顶点作为一棵树,边集=ø;                                                        O(n)

2)依权值递增序对图G的边排序,结果为E[0..e-1]    O(elge)

3)依次检测E中的各边(u,v):                                    O(elge)

     3.1) 若u和v分属于T中两棵不同的树,则将该边加入T,并合并u和v分属的两棵树

     3.2) 若T中所有顶点尚未属于一棵树,转3)


猜你喜欢

转载自blog.csdn.net/liangwgl/article/details/78674924