最小生成树的Kruskal算法

    最小生成树是连接图中所有顶点代价最小的树,通用算法是对于最小生成树的一个顶点子集A,设全体顶点集合为V,则跨越集合{A,V-A}中最小的的边为安全边,可以加入到最小生成树中。

   Kruskal算法采用了不相交的集合森林,把每一个顶点初始化为一个单元素的集合,我再定义了一个边的结构,用于连接两个不同的集合。先用最小堆,以权重非递减的顺序处理边,若边的两个顶点不在同一个集合中,则将他们合并到同一个集合中,如此循环,知道所有的集合变为1个集合为止。

// disjoint_set_forest.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<iostream>
#include<time.h>
#include<queue> 
using namespace std;
typedef int ElementType;
#define numOfVertex 10       //图中顶点的个数
typedef int vertex;



//不相交的集合森林//////////////////////////////////
typedef struct TreeNode *Node;
struct TreeNode
{
	ElementType key;
	int rank;
	Node parent;
};

//生成只有一个元素的新集合/////////////////////////////////////////
Node makeSet(ElementType x)
{
	Node node = (Node)malloc(sizeof(TreeNode));
	node->key = x;
	node->rank = 0;
	node->parent = node;
	return node;
}

//这里传递的参数不能是ElementType类型,因为一开始所有的点都被初始化为一个集合,所以用node类型
Node findSet(Node node)
{
	if (node != node->parent)
		node->parent = findSet(node->parent);
	return node->parent;
}

//连接两个集合的函数//////////////////////////////////////////////////

Node Link(Node node1, Node node2)
{
	if (node1->rank > node2->rank)
	{
		node2->parent = node1;
		return node1;
	}
	else
	{
		node1->parent = node2;
		if (node1->rank == node2->rank)
			node2->rank++;
		return node2;
	}
}

Node Union(Node x, Node y)
{
	return Link(findSet(x), findSet(y));
}
///////////////////////////////////////////////////////////////////////////

//边的结构,重定义了操作符//////////////////////////////////////////////
struct Edge
{
	Node node1, node2;     //边的两个顶点
	int weight;            //边的权重

	friend bool operator< (Edge edge1, Edge edge2)  //重定义运算符
	{
		return edge1.weight > edge2.weight;   //因为优先队列默认是<,因此若要形成最小堆,用>来重定义<
	}
};

void Mst_Kruskal(int graph[numOfVertex][numOfVertex])
{
	//先把每一个顶点生成一个单独的集合,以0为起点
	Node node[numOfVertex];
	for (int i = 0; i < numOfVertex; i++)
		node[i] = makeSet(i);

	//初始化边的结构
	Edge edgeTemp;
	priority_queue<Edge> edgess;  //最小堆
	
	for (int i = 0; i < numOfVertex; i++)
		for (int j = i + 1; j < numOfVertex; j++)
		{
			if (graph[i][j] != 0)
			{
				edgeTemp.weight = graph[i][j];
				edgeTemp.node1 = node[i];
				edgeTemp.node2 = node[j];
				edgess.push(edgeTemp);
			}
		}

	//用队列来存放选中的边
	queue<Edge> result;
	while (!edgess.empty())
	{
		if (findSet(edgess.top().node1) != findSet(edgess.top().node2))
		{
			result.push(edgess.top());
			Union((edgess.top()).node1, (edgess.top()).node2);
		}
		edgess.pop();
	}

	//打印选中的边
	while (!result.empty())
	{
		edgeTemp = result.front();
		result.pop();
		cout << edgeTemp.node1->key << "----" << edgeTemp.node2->key << endl;;
	}
}


int main()
{
	//用初始化一个邻接矩阵的权重,注意只用到了上三角矩阵
	srand((int)time(0));   //产生随机数种子
	int graph[numOfVertex][numOfVertex];
	for(int i=0;i<numOfVertex;i++)
		for (int j = i+1; j < numOfVertex; j++)
		   graph[i][j]= rand() % 20;

	//打印初始化后的邻接矩阵
	for (int i = 0; i < numOfVertex; i++) {
		for (int k = 0; k < i + 1; k++) cout << ' ' << '\t';
		for (int j = i + 1; j < numOfVertex; j++) {
			cout << graph[i][j] << '\t';
		}
		cout << endl;
	}
    
	//调用最小生成树的算法
	Mst_Kruskal(graph);
	while (1);
    return 0;
}

  

posted @ 2017-04-18 15:56  lineaar  阅读(190)  评论(0编辑  收藏  举报