标签:没有 跳过 组成 有一个 查找 取出 保留 起点 并集
在数据结构的教材上,讲到的图的最小生成树算法有两种,一种是Prim(普利姆)算法,一种是Kruskal(克鲁斯卡尔)算法。
两种算法的生成思路有所不同:
Prim算法:
算法思想:
算法思想就是每次找到一个距离生成集合最近的点,加入,然后更新距离剩余点之间的距离,继续迭代。
算法步骤:
1.任意选择一个点作为起点,将该点标记为已加入最小生成树,使用一个数组表示该点已加入,join[i] = 1表示i点已加入集合;
2.将最小生成树集合作为整体,计算到其他未加入该集合的点(jion[i] == 0的点)之间的距离,使用dis[i]表示,dis[i] 表示集合距离点i之间的距离;
3.然后找出dis[i] 中距离最小的,那么 i 就是下一个要加入集合的点
4. 将join[i]赋值为1,表示已加入
5. 重新计算dis[i]。因为有新的点加入,判断该点的加入是否使集合距离其他未加入的点之间的距离变小,如果有变小,则更新dis[i]。
6.继续执行步骤3,直到所有的点都加入join数组(其实是查找n-1次后自动结束,因为指定的起始点,所有只需要再查找n-1次,即for循环从2到n即可)
疑问:Prim算法求得了最小代价,可没有保留下生产路径,不知道是不是自己的理解还不到位或者代码实现不合理。
Kruskal算法:
算法思想:
首先将所有的边按照权重从小到大排序,然后依次取出一条边,尝试将组成集合。如果两个点已经在同一个集合,说明已经添加了,则跳过;如果尚未加入集合,这组成一个新的集合;如果是在不同的集合,则将集合合并,形成一个新的集合,直到取出n-1条有效的边或者所有点都在一个集合中,则表示已生成。
1.使用排序算法将边按权重从小到大排序
2.初始时,点均为构成集合(或者说自成集合,这里理解为未成集合),使用join数组表示集合,初始是join[i]均为0.
3.取出一条边,判断两个点 i,j
1)如果group[i],group[j] 都为0,则说明都还没有加入集合,那么设置group[i] = group[j] = count (count用来表示加入的边数,也能够用来区分集合)
2)如果group[i],group[j] 不相等,说明两个点不在同一个集合。
如果i,j有一个的join值为0,说明未加入,那么只需设置这个点的join值也已加入的那个点一致。
如果两个点都已加入集合,但是处在不同结合,那么此时就需要合并集合。(变量group,把两个集合的点设置为同样的值)
4.所有点在group里对应的值一致,表示形式了最小生成树集合。
标签:没有 跳过 组成 有一个 查找 取出 保留 起点 并集
原文地址:https://www.cnblogs.com/buxiangbuliang/p/9216944.html