带权无向图的最小生成树的构造

  1 /*MST.cpp 带权无向图的最小生成树的构造*/
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #define MAXV 100
  5 #define MaxSize 1000
  6 #define INF 32767
  7 typedef int InfoType;
  8 
  9 typedef struct 
 10 {
 11     int no;                        /*顶点编号*/
 12     InfoType info;                /*顶点其他信息*/
 13 } VertexType;                    /*顶点类型*/
 14 
 15 typedef struct                  /*图的定义*/
 16 {
 17     int edges[MAXV][MAXV];         /*邻接矩阵*/
 18     int n, e;                   /*顶点数,弧数*/
 19     VertexType vexs[MAXV];        /*存放顶点信息*/
 20 } MGraph;                        /*图的邻接矩阵类型*/
 21 
 22 void Prim(MGraph g, int v)      /*普里姆算法*/
 23 {
 24     int lowcost[MAXV];            /*顶点i是否在U中*/
 25     int min;
 26     int closest[MAXV], i, j, k;
 27     
 28     for (i = 0; i < g.n; i++)              /*给lowcost[]和closest[]置初值*/
 29     {    
 30         lowcost[i] = g.edges[v][i];
 31         closest[i] = v;
 32     }
 33     
 34     for (i = 1; i < g.n; i++)              /*找出n-1个顶点*/
 35     {
 36         min = INF;
 37         
 38         for (j = 0; j < g.n; j++)       /*在(V-U)中找出离U最近的顶点k*/
 39         {
 40             if (lowcost[j] != 0 && lowcost[j] < min) 
 41             {
 42                 min = lowcost[j];
 43                 k = j;            /*k记录最近顶点的编号*/
 44             }
 45         }
 46         
 47         printf("边(%d,%d)权为:%d\n", closest[k], k, min);
 48         lowcost[k] = 0;             /*标记k已经加入U*/
 49         
 50         for (j = 0; j < g.n; j++)       /*修改数组lowcost和closest*/
 51         {
 52             if (g.edges[k][j] != 0 && g.edges[k][j] < lowcost[j])
 53             {
 54                 lowcost[j] = g.edges[k][j];
 55                 closest[j] = k; 
 56             }
 57         }
 58     }
 59 }
 60 
 61 typedef struct 
 62 {    
 63     int u;                        /*边的起始顶点*/
 64     int v;                        /*边的终止顶点*/
 65     int w;                        /*边的权值*/
 66 } Edge;                         /*带权边的存储结构*/
 67 
 68 int cmp(const void *a,const void *b) 
 69 { 
 70     return (*(Edge *)a).w > (*(Edge *)b).w ? 1 : -1; 
 71 }
 72 
 73 void Kruskal(MGraph g)              /*克鲁斯卡尔算法*/
 74 {
 75     int i, j, u1, v1, sn1, sn2, k;
 76     int vset[MAXV];
 77     Edge E[MaxSize];                /*存放所有边*/
 78     
 79     k = 0;                            /*E数组的下标从0开始计*/
 80     for (i = 0; i < g.n; i++)        /*由g产生的边集E*/
 81     {
 82         for (j = 0; j < g.n; j++)
 83         {
 84             if (g.edges[i][j] != 0 && g.edges[i][j] != INF)
 85             {
 86                 E[k].u = i;
 87                 E[k].v = j;
 88                 E[k].w = g.edges[i][j];
 89                 k++;
 90             }
 91         }
 92     }
 93     
 94     qsort(E, k, sizeof(E[0]), cmp);     /*采用快速排序对E数组按权值递增排序*/
 95 
 96     for (i = 0; i < g.n; i++) vset[i] = i;            /*初始化辅助数组*/
 97         
 98     k = 1;                             /*k表示当前构造生成树的第几条边,初值为1*/
 99     j = 0;                             /*E中边的下标,初值为0*/
100     while (k < g.n)                   /*生成的边数小于n时循环*/
101     {    
102         u1 = E[j].u;
103         v1 = E[j].v;                /*取一条边的头尾顶点*/
104         sn1 = vset[u1];
105         sn2 = vset[v1];             /*分别得到两个顶点所属的集合编号*/
106         
107         if (sn1 != sn2)               /*两顶点属于不同的集合,该边是最小生成树的一条边*/
108         {    
109             printf("边(%d,%d)的权为:%d\n", u1, v1, E[j].w);
110             k++;                    /*生成边数增1*/
111             for (i = 0; i < g.n; i++)   /*两个集合统一编号*/
112                 if (vset[i] == sn2)      /*集合编号为sn2的改为sn1*/
113                     vset[i] = sn1;
114         }
115         
116         j++;                           /*扫描下一条边*/
117     }
118 }
119 
120 typedef struct node
121 {    
122     int rank;        /*结点对应秩*/
123     int parent;        /*结点对应双亲下标*/
124 } UFSTree;            /*并查集树结点类型*/
125 
126 void MAKE_SET(UFSTree t[], int n)    /*初始化并查集树*/
127 { 
128     int i;
129     
130     for (i = 0; i < n; i++)        /*顶点编号从0到n-1*/
131     {
132         t[i].rank = 0;        /*秩初始化为0*/
133         t[i].parent = i;        /*双亲初始化指向自已*/
134     }
135 }
136 
137 int FIND_SET(UFSTree t[], int x)    /*在x所在子树中查找集合编号*/
138 {
139     if (x != t[x].parent)                /*双亲不是自已*/
140         return FIND_SET(t, t[x].parent);/*递归在双亲中找x*/
141     else
142         return x;                        /*双亲是自已,返回x*/
143 }
144 
145 void UNION(UFSTree t[], int x, int y)    /*将x和y所在的子树合并*/
146 { 
147     x = FIND_SET(t, x);
148     y = FIND_SET(t, y);
149     if (t[x].rank > t[y].rank)            /*y结点的秩小于x结点的秩*/
150         t[y].parent = x;                /*将y连到x结点上,x作为y的孩子结点*/
151     else                                /*y结点的秩大于等于x结点的秩*/
152     { 
153         t[x].parent = y;                /*将x连到y结点上,y作为x的孩子结点*/
154         if (t[x].rank == t[y].rank)        /*x和y结点的秩相同*/
155             t[y].rank++;                /*y结点的秩增1*/
156     }
157 }
158 
159 void Kruskal1(MGraph g)          /*改进的克鲁斯卡尔算法*/
160 {
161     int i, j, k, u1, v1, sn1, sn2;
162     UFSTree t[MaxSize];
163     Edge E[MaxSize];
164     
165     k = 1;                    /*e数组的下标从1开始计*/
166     for (i = 0; i < g.n; i++)        /*由g产生的边集e*/
167     {
168         for (j = 0; j < g.n; j++)
169         {
170             if (g.edges[i][j] != 0 && g.edges[i][j] != INF)
171             {
172                 E[k].u = i;
173                 E[k].v = j;
174                 E[k].w = g.edges[i][j];
175                 k++;
176             }
177         }
178     }
179     
180     qsort(E, k, sizeof(E[0]), cmp);     /*采用快速排序对E数组按权值递增排序*/
181     MAKE_SET(t, g.n);        /*初始化并查集树t*/
182     k = 1;                   /*k表示当前构造生成树的第几条边,初值为1*/
183     j = 1;                   /*E中边的下标,初值为1*/
184     
185     while (k < g.n)           /*生成的边数小于n时循环*/
186     {    
187         u1 = E[j].u;
188         v1 = E[j].v;        /*取一条边的头尾顶点编号u1和v2*/
189         sn1 = FIND_SET(t, u1);
190         sn2 = FIND_SET(t, v1);  /*分别得到两个顶点所属的集合编号*/
191         
192         if (sn1 != sn2)         /*两顶点属于不同的集合,该边是最小生成树的一条边*/
193         {    
194             printf("边(%d,%d)的权为:%d\n", u1, v1, E[j].w);
195             k++;                /*生成边数增1*/
196             UNION(t, u1, v1);    /*将u1和v1两个顶点合并*/
197         }
198         
199         j++;                   /*扫描下一条边*/
200     }
201 }
202 
203 int main()                  /*主函数*/
204 { 
205     int i, j, n;
206     MGraph g;
207     printf("请输入带权无向图的顶点个数:");/*6*/
208     
209     while (scanf("%d", &n) != EOF) 
210     {
211         printf("请输入带权无向图的邻接矩阵:\n");
212         /*
213         0 5 8 7 32767 3
214         5 0 4 32767 32767 32767
215         8 4 0 5 32767 9
216         7 32767 5 0 5 6
217         32767 32767 32767 5 0 1
218         3 32767 9 6 1 0
219         */
220         for (i = 0; i < n; i++)
221         {
222             for (j = 0; j < n; j++)
223             {
224                 scanf("%d", &g.edges[i][j]);
225             }
226         }
227         
228         g.n = n;
229         printf("\n采用普里姆算法得到的最小生成树为:\n");Prim(g, 0);
230         printf("\n采用克鲁斯卡尔算法得到的最小生成树为:\n");Kruskal(g);
231         printf("\n采用改进的克鲁斯卡尔算法得到的最小生成树为:\n");Kruskal1(g);
232         printf("\n请输入带权无向图的顶点个数:");
233     }
234     
235     return 0;
236 }

 

转载于:https://www.cnblogs.com/yaobing/archive/2012/07/08/2581784.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值