最小生成树(两种算法)

#ifndef MIN_TREE_H
#define MIN_TREE_H

#include<queue>
#include<memory>
#include<limits.h>
#include<iostream>

#include"../data_struct/data_struct.h"
#include"../tool/tool_disjoint_set.h"

/// 最小生成树
/// 假设图中的顶点有n个,则生成树的边有n-1条,多一条会存在回路,少一路则不能把所有顶点联通起来,
/// 如果非要在图中加上权重,则生成树中权重最小的叫做最小生成树
class graph_min_tree
{
public:
    /// 普里姆 时间是复杂度O(n2),适合稠密图。
    static bool prim(const std::shared_ptr<graph_matrix> graph,
                     std::vector<int>& out_weight, std::vector<uint32_t>& out_parent)
    {
        out_weight.resize(graph->vertex.size());
        //保存父节点
        out_parent.resize(graph->vertex.size());

        //取出邻接矩阵的第一行数据,也就是取出第一个顶点并将权和边信息保存于临时数据中
        for (uint32_t i = 1; i < graph->vertex.size(); i++)
        {
            out_weight[i] = graph->matrix[0][i];
            out_parent[i] = 0;
        }

        std::vector<bool> is_visited(graph->vertex.size(), false);
        is_visited[0]=true;
        for (uint32_t i = 1; i < graph->vertex.size(); i++)
        {
            uint32_t index = i;
            int min = INT_MAX;

            for (uint32_t j = 1; j < graph->vertex.size(); j++)
            {
                //用于找出当前节点的邻接点中权值最小的未访问点
                if (out_weight[j] < min && is_visited[j] != true)
                {
                    min = out_weight[j];
                    index = j;
                }
            }

            is_visited[index] = true;

            //从最新的节点出发,将此节点的weight比较赋值
            for (uint32_t j = 0; j < graph->vertex.size(); j++)
            {
                //已当前节点为出发点,重新选择最小边
                if (is_visited[j] != true && graph->matrix[index][j] < out_weight[j])
                {
                    out_weight[j] = graph->matrix[index][j];
                    out_parent[j] = index;
                }
            }
        }

        //是否能够生成树
        for (uint32_t i = 1; i < graph->vertex.size(); i++)
        {
            if (out_weight[i] == INT_MAX)
            {
                return false;
            }
        }
        return true;
    }

    /// 克鲁斯卡尔:这篇我们看看第二种生成树的Kruskal算法
    /// 我们知道Prim算法构建生成树是从”顶点”这个角度来思考的,然后采用“贪心思想”
    /// 来一步步扩大化,最后形成整体最优解,而Kruskal算法有点意思,它是站在”边“这个角度在思考的
    /// 时间复杂度O(elog2e),适合简单图。
    static std::vector<edge> kruskal(const std::shared_ptr<graph_matrix> graph)
    {
        //优先队列,存放树中的边
        std::priority_queue<edge> smallPriorityQueue;

        //并查集
        tool_disjoint_set<uint32_t> disjointSet(graph->vertex);

        //将对角线读入到优先队列
        for (uint32_t i = 0; i < graph->vertex.size(); i++)
        {
            for (uint32_t j = 0; j < graph->vertex.size(); j++)
            {
                //说明该边有权重
                if (i != j && graph->matrix[i][j] != INT_MAX)
                {
                    edge tmp(i, j, graph->matrix[i][j]);
                    smallPriorityQueue.emplace(tmp);
                }
            }
        }

        //最后收集到的最小生成树的边
        std::vector<edge> arr;

        //循环队列
        while (smallPriorityQueue.size() > 0)
        {
            auto edge = smallPriorityQueue.top();
            smallPriorityQueue.pop();

            std::cout<<edge.weight<<std::endl;

            //如果该两点是同一个集合,则剔除该集合
            if (disjointSet.is_same_set(edge.start, edge.end))
            {
                continue;
            }

            arr.emplace_back(edge);

            //然后将startEdge 和 End Union起来,表示一个集合
            disjointSet.union_set(edge.start, edge.end);

            //如果n个节点有n-1边的时候,此时生成树已经构建完毕,提前退出
            if (arr.size() == graph->vertex.size() - 1)
            {
                break;
            }
        }

        return arr;
    }
};

#endif // MIN_TREE_H

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值