【图论】【最小生成树】Prim和Kruskal算法

在数据结构的教材上,讲到的图的最小生成树算法有两种,一种是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里对应的值一致,表示形式了最小生成树集合。

猜你喜欢

转载自www.cnblogs.com/buxiangbuliang/p/9216944.html
今日推荐