数据结构:最小生成树(Kruskal)

算法思想:假设N = { V, {E} }是连通网,则令最小生成树的初始状态为只有n个顶点而无边的非连通图
T = { V, {} },图中每个顶点自成一个连通分量。在E中选择
代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中,否则舍去此边而选择下一条代价最小的边。依次类推,直到T中所有顶点都在同一连通分量上为止。

此算法的
FindInUFS函数由边数e决定,时间复杂度为O(loge),而外面有一个for循环e次,所以Kruskal算法的时间复杂度为O(eloge)。

对比Prim算法与Kruskal算法,Kruskal算法主要针对边来展开,边数少时效率会很高,所以对稀疏图有很大的优势。而Prim算法对于稠密图,即边数非常多的情况会更好一些。



#include <iostream>
#include <string>
#include <queue>
#include <deque>
using namespace std;

#define MAXSIZE 10  //顶点最大个数
typedef string VertexType; //顶点类型
typedef int EdgeType;  //权值类型,有向图(0,1),无向图(权值,无穷大)
#define INFINITY 0xffff
typedef struct  
{
	VertexType Vexs[MAXSIZE];  //顶点向量
	EdgeType arcs[MAXSIZE][MAXSIZE]; //邻接矩阵,可看作为边表
	int iVexNum;  //顶点个数
	int iArcNum;  //边数
}MGraph;
#define SUCCESS 1
#define UNSUCCESS 0
typedef int Status;

//由顶点值得到顶点索引
int GetIndexByVertexVal( const MGraph& MG, VertexType val )
{
	for ( int i = 0; i < MG.iVexNum; ++i )
	{
		if ( val == MG.Vexs[i] )
			return i;
	}
	return -1;
}


//创建无向图
Status CreateGraph( MGraph& MG )
{
	cout << "输入顶点个数以及边数:";
	cin >> MG.iVexNum >> MG.iArcNum;
	cout << "请输入" << MG.iVexNum << "个顶点:";
	for ( int i = 0; i < MG.iVexNum; ++i )
	{
		cin >> MG.Vexs[i];
	}

	for ( int i = 0; i < MG.iVexNum; ++i )
	{
		for ( int j = 0; j < MG.iVexNum; ++j )
		{
			MG.arcs[i][j] = INFINITY;
		}
	}

	cout << "请输入由两点构成的边及其权值:";
	for ( int i = 0; i < MG.iArcNum; ++i )
	{
		VertexType first;
		VertexType second;
		EdgeType weight;
		cin >> first >> second >> weight;
		int m = GetIndexByVertexVal( MG, first );
		int n = GetIndexByVertexVal( MG, second ); 
		if ( m == -1 || n == -1 )
			return UNSUCCESS;

		MG.arcs[m][n] = MG.arcs[n][m] = weight;
	}

	return SUCCESS;
}

typedef struct  
{
	int begin; 
	int end;
	int weight;  //权值

}Edge;

//在并查集中查找
int FindInUFS( int* parent, int k )
{
	while ( parent[k] != k )
	{
		k = parent[k];
	}
	return k;
}

//克鲁斯卡尔算法求最小生成树
void MiniSpanTree_Kruskal( const MGraph& G )
{
	//转换为边集数组
	Edge* pEdge = new Edge[G.iArcNum];
	memset( pEdge, 0, G.iArcNum*sizeof(Edge) );
	int m = 0;
	for ( int i = 1; i < G.iVexNum; ++i )
	{
		int k = i - 1;
		for ( int j = 0; j <= k; ++j )
		{
			if ( G.arcs[i][j] != INFINITY )
			{
				pEdge[m].begin = i;
				pEdge[m].end = j;
				pEdge[m].weight = G.arcs[i][j];
				++m;
			}	
		}
	}
	//按权值从小到大进行排序
	for ( int i = 1; i < G.iArcNum-1; ++i )
	{
		bool flag = false;
		for ( int j = 0; j < G.iArcNum - i; ++j )
		{
			if ( pEdge[j].weight > pEdge[j+1].weight )
			{
				int temp;
				temp = pEdge[j].begin;
				pEdge[j].begin = pEdge[j+1].begin;
				pEdge[j+1].begin = temp;

				temp = pEdge[j].end;
				pEdge[j].end = pEdge[j+1].end;
				pEdge[j+1].end = temp;

				temp = pEdge[j].weight;
				pEdge[j].weight = pEdge[j+1].weight;
				pEdge[j+1].weight = temp;
				
				flag = true;
			}
		}
		if ( !flag )
		{
			break;
		}
	}

	//并查集
	int* parent = new int[G.iArcNum];
	for ( int i = 0; i < G.iArcNum; ++i )
	{
		parent[i] = i;
	}


	for ( int i = 0; i < G.iArcNum; ++i )
	{
		int m = FindInUFS( parent, pEdge[i].begin );
		int n = FindInUFS( parent, pEdge[i].end );
		if ( m != n )
		{
			cout << "(" << pEdge[i].begin << "," << pEdge[i].end 
				<< "," << pEdge[i].weight << ")" << endl;
			parent[m] = n;
		}
	}

	if ( !pEdge )
	{
		delete[] pEdge;
		pEdge = NULL;
	}
	if ( !parent )
	{
		delete[] parent;
		parent = NULL;
	}
}


int main()
{
	MGraph MG;
	CreateGraph( MG );

	//克鲁斯卡尔算法求最小生成树
	cout << "普里姆算法求解最小生成数:" << endl;
	MiniSpanTree_Kruskal( MG );
	cout << endl;
 
	return 0;
} 


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值