图的最小生成树Kruskal算法朴素版(C++)


Kruskal算法先将所有的边按权值由小到大排序,然后从无开始(即每个顶点都是一棵子树),每次选取权值最小不会构成回路的边作为最终最小生成树的一部分。最终能够将多个不连通的子树联合起来构成最小生成树。

时间复杂度为 O(ElogE+V2) 。E为图中的边数,V为图中顶点数。

C++代码如下:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

typedef int DATA_TYPE;  // 权值为int型
const DATA_TYPE NO_EDGE = 10000000;  // 表示没有该边

// 邻接矩阵
struct AdjMatrixGraph
{
    vector<vector<DATA_TYPE> > weights;
};

// 边和权值的配对 <<头结点,尾结点>,权值>
typedef pair<vector<int>, DATA_TYPE> PAIR;
int comp(const PAIR &x, const PAIR &y)
{
    return x.second < y.second;
}

vector<vector<int> > Kruskal(AdjMatrixGraph graph)
{
    vector<vector<int> > MST;   // 最小生成树边结果集合
    int vertexNum = graph.weights.size();  // 顶点总数
    vector<int> setNum;  // 每个顶点所属的子树编号
    vector<PAIR> edgesAndWeights;  // 边和权值配对的向量(便于按值排序)

    for (int i = 0; i < vertexNum; ++i)
    {
        for (int j = 0; j < vertexNum; ++j)
        {
            if (graph.weights[i][j] > 0 && graph.weights[i][j] < NO_EDGE)
            {
                // 获取每一条边的信息
                edgesAndWeights.push_back(make_pair(vector<int>{i, j}, graph.weights[i][j]));
            }
        }
        setNum.push_back(i);  // 初始化每一个顶点都分属不同的子树
    }

    // 对每一条边按权值升序排序
    sort(edgesAndWeights.begin(), edgesAndWeights.end(), comp);

    int k = 1;  // 当前正在构造第几条边

    // 最小生成树总共有vertexNum-1条边
    for (vector<PAIR>::iterator mapIter = edgesAndWeights.begin(); mapIter != edgesAndWeights.end(); ++mapIter)
    {
        int headSet = setNum[mapIter->first[0]];  // 当前边的头结点所属的子树编号
        int tailSet = setNum[mapIter->first[1]];  // 当前边的尾结点所属的子树编号

        // 如果它们分属不同的子树(即连接之后不构成回路),则选择该边
        if (headSet != tailSet)
        {
            MST.push_back(mapIter->first);
            ++k;

            // 更新顶点的所属子树的编号
            for (int i = 0; i < vertexNum; ++i)
            {
                if (setNum[i] == tailSet)
                {
                    setNum[i] = headSet;
                }
            }
        }

        if (k >= vertexNum)
        {
            break;
        }
    }

    return MST;
}

int main(int argc, char *argv[])
{
    // 图邻接矩阵
    // 编号从0开始 若不是先转换
    AdjMatrixGraph graph;
    graph.weights.push_back(vector<DATA_TYPE>{0, 6, 1, 5, NO_EDGE, NO_EDGE});
    graph.weights.push_back(vector<DATA_TYPE>{6, 0, 5, NO_EDGE, 3, NO_EDGE});
    graph.weights.push_back(vector<DATA_TYPE>{1, 5, 0, 5, 6, 4});
    graph.weights.push_back(vector<DATA_TYPE>{5, NO_EDGE, 5, 0, NO_EDGE, 2});
    graph.weights.push_back(vector<DATA_TYPE>{NO_EDGE, 3, 6, NO_EDGE, 0, 6});
    graph.weights.push_back(vector<DATA_TYPE>{NO_EDGE, NO_EDGE, 4, 2, 6, 0});

    vector<vector<int> > MST = Kruskal(graph);

    for (size_t i = 0; i < MST.size(); ++i)
    {
        cout <<"边(" << MST[i][0] << " " << MST[i][1] << ") || 权值: " << graph.weights[MST[i][0]][MST[i][1]] << endl;
    }

    return 0;
}

测试用例图如下:
这里写图片描述

输出结果:
边(0 2) || 权值: 1
边(5 3) || 权值: 2
边(4 1) || 权值: 3
边(2 5) || 权值: 4
边(2 1) || 权值: 5


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com