图的最小生成树算法
来源:互联网 发布:c语言中a=3是什么意思 编辑:程序博客网 时间:2024/06/05 03:52
目录
- 图的最小生成树算法之Prim算法简介
- Prim算法举例及其详解
- Prim代码块
- 图的最小生成树算法之Kruskal算法简介
- Kruskal算法举例及其详解
- Kruskal代码块
图的最小生成树算法之Prim算法简介
1、生成树
如果连通图G的一个子图是一棵包含G的所有顶点的树,则该子图称为G的生成树(SpanningTree)。
生成树是连通图的包含图中的所有顶点的极小连通子图。
图的生成树不惟一。从不同的顶点出发进行遍历,可以得到不同的生成树。
2.算法简单描述
1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;
3).重复下列操作,直到Vnew = V:
a.在集合E中选取权值最小的边(u, v),其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
b.将v加入集合Vnew中,将(u, v)边加入集合Enew中;
4).输出:使用集合Vnew和Enew来描述所得到的最小生成树。
Prim代码块
#include<stdio.h>#include<stdlib.h>#define MAXV 100#define LIMITLESS 9999typedef struct{ int no; //顶点编号 int info; //顶点其他信息 } VertexType;typedef struct{ int n; int e;//定点数,边数 int edges[MAXV][MAXV];//邻接矩阵的数组表现 VertexType vexs[MAXV]; //顶点信息 }MGraph;void creat(MGraph *G){ int i, j, k, w; int start, end; printf("请输入顶点数和边数:\n"); scanf("%d%d", &(G->n), &(G->e)); getchar(); printf("请输入顶点信息:\n"); for (i = 0; i<G->n; i++) { scanf("%d%d", &(G->vexs[i].no), &(G->vexs[i].info)); } for (i = 0; i<G->n; i++) { for (j = 0; j<G->n; j++) { if (i == j) { G->edges[i][j] = 0; } else { G->edges[i][j] = LIMITLESS; } } } printf("请输入 图的顶点 边和它的权值:\n"); for (k = 0; k<G->e; k++) { scanf("%d%d%d", &start, &end, &w); G->edges[start][end] = w; G->edges[end][start] = w;//无向图时用到 }}void print(MGraph *G){ int i, j; printf("顶点数:%d, 边数:%d\n", G->n, G->e); printf("%d个顶点的信息(顶点下标必须从0开始):\n", G->n); for (i = 0; i<G->n; i++) { printf("%5d%5d", G->vexs[i].no, G->vexs[i].info); } printf("\n各个顶点的连接情况:\n"); printf("\t"); for (i = 0; i<G->n; i++) { printf("[%d]\t", i); } printf("\n"); for (i = 0; i<G->n; i++) { printf("[%d]\t", i); for (j = 0; j<G->n; j++) { if (G->edges[i][j] == LIMITLESS) { printf("oo\t"); } else { printf("%d\t", G->edges[i][j]); } } printf("\n"); }}void Prim(MGraph *g, int v){ int i, j, k; int lowcost[MAXV]; int min; int closest[MAXV]; for (i = 0; i < g->n; i++) { lowcost[i] = g->edges[v][i]; closest[i] = v; } for (i = 1; i < g->n; i++)//因为前面已经有了一次初始化,所以剩下的次数为n-1 { min = LIMITLESS; //找到权值最小的邻接点 for (j = 0; j < g->n; j++) { if (lowcost[j] != 0 && lowcost[j] < min) { min = lowcost[j]; k = j; } } printf("边(%d,%d):%d\n", closest[k], k, min); lowcost[k] = 0; //调整lowcost[]和closest[]; for (j = 0; j < g->n; j++) { if (g->edges[k][j] != 0 && g->edges[k][j] < lowcost[j]) { lowcost[j] = g->edges[k][j]; closest[j] = k; } } }}int main(void){ MGraph *g; g = malloc(sizeof(MGraph)); creat(g); print(g); Prim(g,0); system("pause"); return 0;}
测试结果:
参考图纸:
图的最小生成树算法之Kruskal算法简介
假设连通网N=(V,{E})。则令最小生成树的初始状态为只有n个顶点而无边的非连通图T=(V,{}),图中每个顶点自成一个连通分量。
在E中选择最小代价的边,若该边依附的顶点落在T中不同的连通分量中,则将该边加入到T中,否则舍去此边而选择下一条代价最小的边,依次类推,直到T中所有顶点都在同一连通分量上为止。
Kruskal代码块
卡鲁斯卡尔的最小生成树算法要求求得的最小生成树不能出现回路
#include<stdio.h>#include<stdlib.h>#define MAXV 100#define LIMITLESS 9999typedef struct{ int no; //顶点编号 int info; //顶点其他信息 } VertexType;typedef struct{ int n; int e;//定点数,边数 int edges[MAXV][MAXV];//邻接矩阵的数组表现 VertexType vexs[MAXV]; //顶点信息 }MGraph;typedef struct{ int u;//边的起始顶点 int v;//边的终止顶点 int w;//边的权值}Edge;void creat(MGraph *G){ int i, j, k, w; int start, end; printf("请输入顶点数和边数:\n"); scanf("%d%d", &(G->n), &(G->e)); getchar(); printf("请输入顶点信息:\n"); for (i = 0; i<G->n; i++) { scanf("%d%d", &(G->vexs[i].no), &(G->vexs[i].info)); } for (i = 0; i<G->n; i++) { for (j = 0; j<G->n; j++) { if (i == j) { G->edges[i][j] = 0; } else { G->edges[i][j] = LIMITLESS; } } } printf("请输入 图的顶点 边和它的权值:\n"); for (k = 0; k<G->e; k++) { scanf("%d%d%d", &start, &end, &w); G->edges[start][end] = w; G->edges[end][start] = w; }}void print(MGraph *G){ int i, j; printf("顶点数:%d, 边数:%d\n", G->n, G->e); printf("%d个顶点的信息:\n", G->n); for (i = 0; i<G->n; i++) { printf("%5d%5d", G->vexs[i].no, G->vexs[i].info); } printf("\n各个顶点的连接情况:\n"); printf("\t"); for (i = 0; i<G->n; i++) { printf("[%d]\t", i); } printf("\n"); for (i = 0; i<G->n; i++) { printf("[%d]\t", i); for (j = 0; j<G->n; j++) { if (G->edges[i][j] == LIMITLESS) { printf("oo\t"); } else { printf("%d\t", G->edges[i][j]); } } printf("\n"); }}void InsertSort(Edge E[], int n){ int i, j; Edge temp; for (i = 1; i < n; i++) { temp = E[i]; j = i - 1; while (j >= 0 && temp.w < E[j].w) { E[j + 1] = E[j]; j--; } E[j + 1] = temp; } for (i = 0; i < n; i++) { printf("%d %d %d\n", E[i].u, E[i].v, E[i].w); }}void Kruskal(MGraph *g){ int i, j, u1, v1, sn1, sn2, k; int vset[MAXV]; Edge E[MAXV]; //存放所有边 k = 0; //E数组的下标从0开始计 for (i = 0; i<g->n; i++) //由g产生的边集E for (j = 0; j<g->n; j++) if (g->edges[i][j] != 0 && g->edges[i][j] != LIMITLESS) { E[k].u = i; E[k].v = j; E[k].w = g->edges[i][j]; k++; } InsertSort(E, k); //采用直接插入排序对E数组按权值递增排序 for (i = 0; i<g->n; i++) //初始化辅助数组 vset[i] = i; k = 1; //k表示当前构造生成树的第几条边,初值为1 j = 0; //E中边的下标,初值为0 while (k<g->n) //生成的边数小于n时循环 { u1 = E[j].u; v1 = E[j].v; //取一条边的头尾顶点 sn1 = vset[u1]; sn2 = vset[v1]; //分别得到两个顶点所属的集合编号 if (sn1 != sn2) //两顶点属于不同的集合 { printf(" (%d,%d):%d\n", u1, v1, E[j].w); k++; //生成边数增1 for (i = 0; i<g->n; i++) //两个集合统一编号 if (vset[i] == sn2) //集合编号为sn2的改为sn1 vset[i] = sn1; } j++; //扫描下一条边 }}int main(void){ MGraph *g; g = malloc(sizeof(MGraph)); creat(g); print(g); Kruskal(g); system("pause"); return 0;}
测试结果:
参考图纸:
0 0
- 图的最小生成树(prim算法)
- 图的最小生成树算法
- 图的最小生成树算法
- 图的最小生成树Kruskal算法
- 图的最小生成树---Prim算法
- 图的最小生成树算法
- 图的最小生成树算法
- 图的最小生成树---Prim算法
- 最小生成树的算法
- Prim 算法生成的最小生成树
- 图算法--最小生成树
- 算法学习之图的最小生成树Kruskal算法
- 图的最小生成树:Prim算法和Kruskal算法
- 算法:图的普里姆算法最小生成树-数据结构(22)
- 【算法】图的最小生成树(Prim算法)
- 【算法】图的最小生成树(Kruskal算法)
- 图的最小生成树的两种算法
- 最小生成树算法
- coco2d-x 使用Action中的Animate实现动画效果
- ftp的学习
- 正则表达式
- JavaScript利用对象去重复值
- MySQL B+树索引和哈希索引的区别
- 图的最小生成树算法
- Spring的AOP原理
- 表达式求值(顺序栈实现)
- 6. ZigZag Conversion
- Backtrader量化平台教程(二):Strategy类
- jvm
- Spark RPC之RpcEnvFileServer
- 设计模式学习--解释器模式
- pycharm搭建django