zoukankan      html  css  js  c++  java
  • 最小生成树的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 << ' ' << '	';
    		for (int j = i + 1; j < numOfVertex; j++) {
    			cout << graph[i][j] << '	';
    		}
    		cout << endl;
    	}
        
    	//调用最小生成树的算法
    	Mst_Kruskal(graph);
    	while (1);
        return 0;
    }
    

      

  • 相关阅读:
    软件工程第三次作业
    软件工程第二次作业
    Java基础篇
    2018软件工程第一次作业
    网络基础知识(http请求)
    linux命令
    添加电子称程序
    多线程Demo
    关闭一个winform窗体刷新另外一个
    通过WebApi取出XML数据
  • 原文地址:https://www.cnblogs.com/linear/p/6728246.html
Copyright © 2011-2022 走看看