Kruskal算法

用Kruskal算法计算最小生成树时,将结点分成不同的集合,一开始所有的结点都在不同的集合 

将所有的边排序后(按照权值进行从小到大排序) 然后看每边的两个结点是否属于不同集合,

如果不是,则可以将这条表加到最小生成树中,并把这两个结点放到同一个集合中,然后如此类推,

直到最小生成树中有了n-1条边 

测试用例:

上面说的那个集合,我用两个map来实现,好久没敲C++的代码,写的不好请见谅

Edge.h

复制代码
#ifndef GUARD_Edge_h
#define GUARD_Edge_h

#include <string> 

using std::string;

class Edge
{
public:
    Edge() {}

    Edge(const string& StartNode,const string& EndNode, double weight):
        StartNodeID(StartNode),EndNodeID(EndNode),Weight(weight) {}

    string StartNodeID;
    string EndNodeID;
    double Weight;
};

bool Compare(const Edge& e1,const Edge& e2);

#endif
复制代码

 

Node.h

复制代码
#ifndef GUARD_Node_h
#define GUARD_Node_h

#include <string>
#include <vector>
#include "Edge.h"

using std::string;
using std::vector;

//结点以及这个结点所有的出边
class Node
{
public:
    Node(const string& ID,const vector<Edge>& edgeList) :
      _ID(ID),_edgeList(edgeList) {}

    Node(const string& ID):_ID(ID) {}

    string GetID()
    {
        return _ID;
    }

    vector<Edge> GetEdgeList()
    {
        return _edgeList;
    }

    void AddEdge(const Edge& edge)
    {
        _edgeList.push_back(edge);
    }

private:
    string _ID;
    vector<Edge> _edgeList;
};

#endif
复制代码

 

Graph.h

复制代码
#ifndef GRUAD_Graph_h
#define GRUAD_Graph_h

#include <string>
#include <map>
#include <vector>
#include "Node.h"
#include "MSTree.h"

using std::string;
using std::map;
using std::vector;

class Graph
{
    typedef map<string,double> Path;
    typedef map<string,Path> G;

public:
    Graph(const vector<Node>& nodeList):
      _nodeList(nodeList) {};
    MSTree GetMST();

private:
    G graph;
    vector<Node> _nodeList;
};

#endif
复制代码

 

Graph.cpp

复制代码
#include "Graph.h"
#include <iostream>
#include <algorithm>

using namespace std;

MSTree Graph::GetMST()
{
    G s;//集合s
    vector<Node>::size_type i;
    vector<Node>::size_type j;

    //储存所有边的容器
    vector<Edge> edgeList;

    //初始化s集合,使每个顶点分属于不同的集合
    for (i=0;i<_nodeList.size();i++)
    {
        string NodeID=_nodeList[i].GetID();
        s[NodeID][NodeID]=1;

        for (j=0;j<_nodeList[i].GetEdgeList().size();j++)
            edgeList.push_back((_nodeList[i].GetEdgeList())[j]);
    }

    //把边按照权值进行从小到大排序
    sort(edgeList.begin(),edgeList.end(),Compare);
    /*for (vector<Edge>::size_type ii=0;ii<edgeList.size();ii++)
    {
        cout<<edgeList[ii].StartNodeID<<"->"<<edgeList[ii].EndNodeID
            <<" "<<edgeList[ii].Weight<<endl;
    }*/

    vector<Node>::size_type k=1;  //计数
    vector<Edge>::size_type d=0;
    string m1,m2;  //记录一条边的两个顶点分别在哪个集合
    j=0;

    vector<Edge> Tree; //储存最小生成树的边
    double weight=0;   //以及总权值

    while(k<_nodeList.size())
    {
        for (i=0;i<_nodeList.size();i++)
        {
            string curNodeID=_nodeList[i].GetID();

            if (s[curNodeID][edgeList[d].StartNodeID]==1)
                m1=curNodeID;
            if(s[curNodeID][edgeList[d].EndNodeID]==1)
                m2=curNodeID;
        }
        
        //如果一条边的两个顶点属于不同的集合
        //就把这条边加到树中
        if (m1!=m2)
        {
            //cout<<m1<<" "<<m2<<endl;
            Tree.push_back(edgeList[d]);
            weight+=edgeList[d].Weight;
            
            k++;
            for (j=0;j<_nodeList.size();j++)
            {
                // 合并两个集合
                s[m1][_nodeList[j].GetID()]=s[m1][_nodeList[j].GetID()]
                                            ||s[m2][_nodeList[j].GetID()];
                // 将另一个集合置空
                s[m2][_nodeList[j].GetID()]=0;
            }
        }
        d++;
    }

    MSTree msTree(Tree,weight);
    return msTree;
}
复制代码

 

MSTree.h

复制代码
#ifndef GUARD_MSTree_h
#define GUARD_MSTree_h

#include <vector>
#include "Edge.h"

using std::vector;

//最小生成树,含有n-1条边以及
//所有边的总权值
class MSTree
{
public:
    MSTree(const vector<Edge>& edgeList,double weight):
      _msTree(edgeList),_weight(weight){}
    vector<Edge> GetEdgeList() {return _msTree;}
    double GetWeight() {return _weight;}

private:
    vector<Edge> _msTree;
    double _weight;
};


#endif
复制代码

 

main.cpp

复制代码
#include <iostream>
#include "Graph.h"
#include <map>
#include <vector>

using namespace std;

vector<Node> Init()
{
    Edge edge;

    Node A("A");
    edge.StartNodeID="A";
    edge.EndNodeID="B";
    edge.Weight=8;
    A.AddEdge(edge);

    edge.StartNodeID="A";
    edge.EndNodeID="D";
    edge.Weight=5;
    A.AddEdge(edge);

    Node B("B");
    edge.StartNodeID="B";
    edge.EndNodeID="D";
    edge.Weight=3;
    B.AddEdge(edge);

    edge.StartNodeID="B";
    edge.EndNodeID="E";
    edge.Weight=10;
    B.AddEdge(edge);

    edge.StartNodeID="B";
    edge.EndNodeID="C";
    edge.Weight=12;
    B.AddEdge(edge);

    Node C("C");
    edge.StartNodeID="C";
    edge.EndNodeID="E";
    edge.Weight=6;
    C.AddEdge(edge);

    edge.StartNodeID="C";
    edge.EndNodeID="F";
    edge.Weight=2;
    C.AddEdge(edge);

    Node D("D");
    edge.StartNodeID="D";
    edge.EndNodeID="F";
    edge.Weight=7;
    D.AddEdge(edge);

    edge.StartNodeID="D";
    edge.EndNodeID="G";
    edge.Weight=15;
    D.AddEdge(edge);

    Node E("E");
    edge.StartNodeID="E";
    edge.EndNodeID="F";
    edge.Weight=9;
    E.AddEdge(edge);

    Node F("F");
    Node G("G");

    vector<Node> nodeList;
    nodeList.push_back(A);
    nodeList.push_back(B);
    nodeList.push_back(C);
    nodeList.push_back(D);
    nodeList.push_back(E);
    nodeList.push_back(F);
    nodeList.push_back(G);

    return nodeList;
}

int main()
{
    vector<Node> nodeList=Init();
    Graph graph(nodeList);
    MSTree msTree=graph.GetMST();

    //得到计算结果
    vector<Edge> edgeList=msTree.GetEdgeList();

    cout<<"Minimum Spanning Tree: "<<endl;
    for (vector<Edge>::size_type i=0;i<edgeList.size();i++)
    {
        cout<<edgeList[i].StartNodeID<<"->"<<edgeList[i].EndNodeID
            <<" "<<edgeList[i].Weight<<endl;
    }
    cout<<"Total weight: "<<msTree.GetWeight()<<endl;
    return 0;
}
复制代码


结果:

 

于是我们得到的最小生成树为:

 

Kruskal算法是一种用来求加权连通图的最小生成树(MST)的算法,由Joseph Kruskal在1956年发表。该算法的基本思想是按照边的权值从小到大的顺序选择边,并保证这些边不构成回路。具体做法是首先构造一个只含有n个顶点的森林,然后依据权值从小到大从连通网中选择边加入到森林中,并保证森林中不产生回路,直至森林变成一棵树为止。 使用Kruskal算法求解最小生成树的过程主要有两个关键步骤。首先,需要对图的所有边按照权值大小进行排序。其次,需要判断在将边添加到最小生成树中时是否会形成回路。通过这两个步骤,Kruskal算法能够找到图的最小生成树。 总结来说,Kruskal算法通过按照边的权值从小到大选择边,并保证不形成回路的方式来构建最小生成树。这种算法适用于解决求解加权连通图的最小生成树问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Kruskal算法简易教程(附最全注释代码实现)](https://blog.csdn.net/hzf0701/article/details/107933639)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [克鲁斯卡尔算法Kruskal)详解](https://blog.csdn.net/weixin_45829957/article/details/108001882)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值