kruskal算法实现最小生成树

之前写了prim算法实现最小生成树,接下来看看kruskal算法
对于给定的图G,令其最小生成树T初始时为G到n个顶点(边为0),然后将G的边上权重从小到大排序,每次选取最小到边,如果选中的边的两个顶点是连通的,则删除该条边,选取下一条边,如果选中的两个顶点不连通,那么该边加入到T中,如此重复,直到所有顶点都连通
看图:
这里写图片描述

好了,接下来就是画思想为实践了,不妨先定义一个定位权重的函数

//根据权重定位边的两个顶点,值得注意可能有多条边权重相同
void adjaMultiList::locateInfo(double weight, vector<int> &a, vector<int> &b)
{
    for (int i = 0; i < iVertex; ++i)
    {
        edgeNode*p = verNode[i].firstEdge;
        while (p)
        {
            if (p->info == weight)
            {
                a.push_back(p->aVertex);
                b.push_back(p->bVertex);

            }
            p = p->aLink;
        }
    }
}
void adjaMultiList::kruskalTree()
{
    cout << "最小生成树的各边及权值为:" << endl;

    /*
    kruskal算法关键问题是如何判断在选中若干条边后,某两个顶点是否连通,可以根据书上的一种简单的
    方法,定义一个一维数组f,开始时每个顶点为一个连通分量,f[i]=i;比如加入边a,b后,可以令f[a]=a[b]
    那么以后判断时就可以根据f[a]和f[b]是否相等即可
    */
    int f[MAXVERTEX];
    int u[MAXVERTEX];//u用来保存图的最小生成树的顶点
    for (int i = 0; i < iVertex; ++i)//初始时为空
    {
        u[i] = -1;
        f[i] = i;
    }
    int m = 0;//m保存u中顶点个数
    int n = 0;//n表示已经选中的边数




    vector<double> dEdge;//保存所有边
    for (int i = 0;i < iVertex;++i)
    {
        edgeNode*p = verNode[i].firstEdge;
        while (p)
        {
            dEdge.push_back(p->info);
            p = p->aLink;
        }
    }
    sort(dEdge.begin(), dEdge.end());//排序



    while(n!=iVertex-1)//如果边数为顶点数-1,则整个图连通
    {
        vector<int> aVec;
        vector<int> bVec;
        double weight = *dEdge.begin();
        locateInfo(weight, aVec, bVec);
        for (int i = 0; i < aVec.size(); ++i)
        {
            int a = aVec[i];
            int b = bVec[i];
            if (m == 0)//当u中没有顶点时,肯定可以连,并且增加两个顶点
            {
                cout << "边: " << a<< " " << b << " 权重: " << *dEdge.begin() << endl;
                m += 2;
                u[0] = a;
                u[1] = b;
                f[a] = f[b];

                auto p = dEdge.begin();
                dEdge.erase(p);

                ++n;
                //continue;
            }

            else
            {
                int countA = 0;
                int countB = 0;
                for (int j = 0; j < m; j++)
                {
                    if (u[j] == a)
                        ++countA;
                    if (u[j] == b)
                        ++countB;
                }

                if (countA&&countB)//如果两个都在u中
                {
                    //两个顶点都在u中,且是连通的,那么不能连
                    if (f[a] == f[b])
                    {
                        auto p = dEdge.begin();
                        dEdge.erase(p);
                    }
                    else
                    {
                        cout << "边: " << a << " " << b << " 权重: " << *dEdge.begin() << endl;
                        auto p = dEdge.begin();
                        dEdge.erase(p);
                        ++n;
                        //这里要注意,将a以及所有与a连通的顶点的f[]值都改为b的,或者反过来
                        for (int i1 = 0; i1 < iVertex; i1++)
                        {
                            if (f[i1] == f[a])
                                f[i1] = f[b];
                        }
                    }
                    continue;
                }

                if (!countA && !countB)//两个顶点均不在u中
                {
                    m += 2;
                    u[m - 2] = a;
                    u[m - 1] = b;
                    f[a] = f[b];
                    cout << "边: " << a << " " << b << " 权重: " << *dEdge.begin() << endl;
                    auto p = dEdge.begin();
                    dEdge.erase(p);
                    ++n;
                    continue;
                }

                if (countA + countB == 1)//有一个结点在u中
                {
                    cout << "边: " << a << " " << b << " 权重: " << *dEdge.begin() << endl;
                    ++m;
                    if (countA)
                    {
                        u[m - 1] = b;
                        //b不在u中,直接f[b]=f[a]即可
                        f[b] = f[a];
                    }

                    else
                    {
                        u[m - 1] = a;
                        //相反
                        f[a] = f[b];
                    }

                    auto p = dEdge.begin();
                    dEdge.erase(p);
                    ++n;
                    continue;
                }
            }


        }
    }

}

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值