#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