数据结构:最小生成树--Kruskal算法

时间:2022-12-20 11:37:55

数据结构:最小生成树--Kruskal算法

标签: Kruskal算法并查集kruskal数据结构 2308人阅读 评论(1)收藏举报 数据结构:最小生成树--Kruskal算法分类: 作者同类文章X

    目录(?)[+]

    1. Kruskal算法
    2. 算法说明
    3. 代码

                               Kruskal算法

    Kruskal算法

        求解最小生成树的另一种常见算法是Kruskal算法,它比Prim算法更直观。从直观上看,Kruskal算法的做法是:每次都从剩余边中选取权值最小的,当然,这条边不能使已有的边产生回路。

    手动求解会发现Kruskal算法异常简单,下面是一个例子

    数据结构:最小生成树--Kruskal算法

    先对边的权值排个序:1(0,1) 2(2,6) 4(1,3) 6(1,2) 8(3,6) 10(5,6) 12(3,5) 15(4,5) 20(0,1)

    首选边1(0,1)、2(2,6)、4(1,3)、6(1,2),此时的图是这样

    数据结构:最小生成树--Kruskal算法

    数据结构:最小生成树--Kruskal算法

    显然,若选取边8(3,6)会出现环,则必须抛弃8(3,6),选择下一条10(5,6)没有问题,此时图变成这样

    数据结构:最小生成树--Kruskal算法

    数据结构:最小生成树--Kruskal算法

    显然,12(3,5)同样不可取,选取15(4,5),边数已达到要求,算法结束。最终的图是这样的

    数据结构:最小生成树--Kruskal算法

    数据结构:最小生成树--Kruskal算法

    算法逻辑人很容易理解,但用代码判断当前边是否会引起环的出现,则很棘手。

    算法说明

        为了判断环的出现,我们换个角度来理解Kruskal算法的做法:初始时,把图中的n个顶点看成是独立的n个连通分量,从树的角度看,也是n个根节点。我们选边的标准是这样的:若边上的两个顶点从属于两个不同的连通分量,则此边可取,否则考察下一条权值最小的边。

        于是问题又来了,如何判断两个顶点是否属于同一个连通分量呢?这个可以参照并查集的做法解决。它的思路是:如果两个顶点的根节点是一样的,则显然是属于同一个连通分量。这也同样暗示着:在加入新边时,要更新父节点。具体细节看代码:

    代码

    [cpp] view plain copyprint?
    1. #include<iostream>   
    2. #include<algorithm>  
    3. using namespace std;  
    4. #define MAXWEIGHT 100  
    5. /* 
    6. 全局变量 
    7. numV顶点数 
    8. numE边数 
    9. */  
    10. int numV, numE;  
    11. //边  
    12. typedef struct edge_tag  
    13. {  
    14.     int tail;  
    15.     int head;  
    16.     int weight;  
    17. }Edge;  
    18. //检测边  
    19. bool checkEdge(int tail, int head, int weight)  
    20. {  
    21.     if (tail == head  
    22.         || tail < 0 || tail >= numV  
    23.         || head < 0 || head >= numV  
    24.         || weight <= 0 || weight >= MAXWEIGHT)  
    25.         return false;  
    26.     return true;  
    27. }  
    28. //输入边  
    29. void inputEdge(Edge *edge, int numE)  
    30. {  
    31.     int i, tail, head, weight;  
    32.     cout << "输入边的起点、终点和权值" << endl;  
    33.     i = 0;  
    34.     while (i < numE)  
    35.     {  
    36.         cin >> tail >> head >> weight;  
    37.         while (!checkEdge(tail, head, weight))  
    38.         {  
    39.             cout << "输入错误!重新输入" << endl;  
    40.             cin >> tail >> head >> weight;  
    41.         }  
    42.         edge[i].tail = tail;  
    43.         edge[i].head = head;  
    44.         edge[i].weight = weight;  
    45.         i++;  
    46.     }  
    47. }  
    48. int cmp(const void *edge1, const void *edge2)  
    49. {  
    50.     return ((Edge*)edge1)->weight - ((Edge*)edge2)->weight;  
    51. }  
    52.   
    53. //并查集的常见操作  
    54. /* 
    55. 压缩查找 
    56. 查找child的根节点 
    57. */  
    58. int Find(int child, int *parent)  
    59. {  
    60.     if (parent[child] == child)  
    61.         return child;  
    62.     parent[child] = Find(parent[child], parent); //压缩路径  
    63.     return parent[child];  
    64. }  
    65. //合并  
    66. bool Union(Edge *e, int *parent, int *childs)  
    67. {  
    68.     //处于同一个棵树中,则不能合并,否则会出现环  
    69.     int root1, root2;  
    70.     root1 = Find(e->tail, parent);  
    71.     root2 = Find(e->head, parent);  
    72.     if (root1 != root2)  
    73.     {  
    74.         //把小树合并到大树根下  
    75.         if (childs[root1] > childs[root2])  
    76.         {  
    77.             parent[root2] = root1;  
    78.             childs[root1] += childs[root2] + 1;  
    79.         }  
    80.         else  
    81.         {  
    82.             parent[root1] = root2;  
    83.             childs[root2] += childs[root2] + 1;  
    84.         }  
    85.         return true;  
    86.     }  
    87.     return false;  
    88. }  
    89. /* 
    90. Kruskal算法 
    91. 求最小生成树 
    92. */  
    93. void Kruskal(int numV, int numE)  
    94. {  
    95.     //边的集合  
    96.     Edge *edge = new Edge[numE];  
    97.     inputEdge(edge, numE);  
    98.     /* 
    99.     parent[i]是顶点i的父顶点 
    100.     childs[i]是顶点i的孩子数 
    101.     child的复数是children,这里的childs是杜撰的 
    102.     */  
    103.     int *parent = new int[numV];  
    104.     int *childs = new int[numV];  
    105.     //初始化  
    106.     for (int i = 0; i < numV; i++)  
    107.     {  
    108.         /* 
    109.         初始时,每一个顶点都是根,且无孩子 
    110.         把每个顶点的的父节点设置为自身下标,也是标明类别 
    111.         */  
    112.         parent[i] = i;  
    113.         childs[i] = 0;  
    114.     }  
    115.     //对边按权值进行从小到大排序  
    116.     qsort(edge, numE, sizeof(Edge), cmp);  
    117.     int i, count;  
    118.     i = count = 0;  
    119.     cout << "最小生成树的边..." << endl;  
    120.     while (i < numE)  
    121.     {  
    122.         if (Union(&edge[i], parent, childs))  
    123.         {  
    124.             cout << edge[i].tail << "---" << edge[i].head << endl;  
    125.             count++;  
    126.         }  
    127.         if (count == numV - 1)  //边数达到要求  
    128.             break;  
    129.         i++;  
    130.     }  
    131.     if (count != numV - 1)  
    132.         cout << "此图为非连通图!无法构成最小生成树。" << endl;  
    133.     delete[]edge;  
    134.     delete[]parent;  
    135.     delete[]childs;  
    136. }  
    137. //检测顶点数和边数  
    138. bool checkVE(int numV, int numE)  
    139. {  
    140.     if (numV <= 0 || numE <= 0 || numE > numV*(numV - 1) / 2)  
    141.         return false;  
    142.     return true;  
    143. }  
    144. int main()  
    145. {  
    146.     cout << "******Kruskal***by David***" << endl;  
    147.     cout << "输入顶点数、边数 ";  
    148.     cin >> numV >> numE;  
    149.     while (!checkVE(numV, numE))  
    150.     {  
    151.         cout << "输入数据有问题!重新输入 ";  
    152.         cin >> numV >> numE;  
    153.     }  
    154.     cout << endl << "Kruskal..." << endl;  
    155.     Kruskal(numV, numE);  
    156.     system("pause");  
    157.     return 0;  
    158. }  
    运行

    数据结构:最小生成树--Kruskal算法




    转载请注明出处,本文地址:http://blog.csdn.net/zhangxiangdavaid/article/details/38414683


    若有所帮助,顶一个哦!


    专栏目录:




    1
    1
       

      相关文章推荐