图的最小生成树之Prim算法及Kruskal算法

最小生成树定义:无向图连通图G中,由所有顶点构成且总价值(连接权值和)最低的一棵树(拓扑结构)称为一个最小生成树。最小生成树顶点为|V|个,边数为|V|-1,没有圈。对任一生成树T,如果将图中一条不属于T的边添加至T,则会产生一个圈,从该圈中除去任意一条边,则会又恢复成生成树。下图为一示例: 对于上面的无向有权连通图,其最小生成树为: 解决最小生成树问题有两种算法Prim算法和...
摘要由CSDN通过智能技术生成

最小生成树

  • 定义:无向图连通图G中,由所有顶点构成且总价值(连接权值和)最低的一棵树(拓扑结构)称为一个最小生成树。
  • 最小生成树顶点为|V|个,边数为|V|-1,没有圈。
  • 对任一生成树T,如果将图中一条不属于T的边添加至T,则会产生一个圈,从该圈中除去任意一条边,则会又恢复成生成树。
  • 下图为一示例:
    这里写图片描述
  • 对于上面的无向有权连通图,其最小生成树为:
    这里写图片描述
  • 解决最小生成树问题有两种算法Prim算法和Kruskal算法,二者都是基于贪心算法的策略。

Prim算法

  • 由于最小生成树包含图中所有顶点。因此可以从顶点以及顶点间的连接权值考虑解决问题。
  • Prim算法考虑顶点以及邻接点,每一步基于贪心的策略,选取未知的且与已知顶点具有最小连接权值的顶点。
  • Prim算法和求带权最短路径Dijkstra算法一样,借助一个状态信息表InfoTable来标记每一步每个顶点的状态。
  • InfoTable中,每个顶点有三个状态:Known(标记顶点是否被声明已知),dist(与开始顶点的距离),Path(上一个被标记已知的顶点)。
  • 与Dijkstra不同的是,这里的状态信息表更新规则为:在每个顶点v被选取以后,对于每个未知的v邻接点, distw=min(distw,weightv,w) d i s t w = m i n ( d i s t w , w e i g h t v , w ) 。另外Prim算法运行在无向图上,注意每条边出现在两个邻接表中。
  • Prim算法运行时间复杂度为 O(|V|2) O ( | V | 2 ) ,使用二叉堆时,运行时间为 O(|E|log|V|) O ( | E | log ⁡ | V | )
template<class T>
void Graph<T>::Prim(int index)      // Prim算法实现,目的是为了改变index顶点的状态信息表
{
    int MinIndex;
    while (1)
    {
        MinIndex = UnknownMinDistVertex(index);     // 寻找当前index顶点的状态信息表的最小dist值的顶点下标
        if (MinIndex == -1)                         // 当MinIndex为-1,表示所有点都被标明已知,结束循环
            break;
        VSet[index].table[MinIndex].Known = true;       // 标记最小dist值的顶点为已知
        // 遍历当前最小dist值的顶点的邻接表
        for (vector<Vertex<T>>::iterator iter = VSet[MinIndex].adj_list.begin(); iter != VSet[MinIndex].adj_list.end();iter++)
        {
            if (!VSet[index].table[iter->value].Known)  // 如果其邻接点未被声明已知,则
                // 如果最小dist顶点与其邻接点的连接权值小于其邻接点原有的dist值,则更新其邻接点的dist值
                if (iter->weight < VSet[index].table[iter->value].dist)
                {
                    VSet[index].table[iter->value].dist = iter->weight;
                    // 更新最小dist顶点的邻接点的Path值为最小dist顶点(的值,为了方便)
                    VSet[index].table[iter->value].Path = VSet[MinIndex].value;     
                }
        }
    }
}

Kruskal算法

  • Kruskal算法同样采取贪心的策略来解决最小生成树问题。和Prim不同的是,Kruskal算法考虑图中的每条边。
  • Kruskal每次选择具有最小连接权值的边,当每次选择的边与已被选择的边不构成圈时,就选定该条边。
  • 当选定的边数到达一定数目|V|-1时,算法终止,所有边会形成一个树即最小生成树。
  • 判断是否形成圈:首先所有顶点各自构成一个集合,当它们之间的边被选定时,合并成一个大集合。算法进行到某一刻时,两个顶点u,v属于同一个集合当且仅当它们连通,如果下一步再出现一条边的两个顶点已经在集合中,则会形成一个圈,则不选择这条边。
  • Kruskal算法每次要寻找一条最小权值边,时间复杂度为
  • 7
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值