Prim算法说明及图解

合集下载

最小生成树的Prim算法以及Kruskal算法的证明

最小生成树的Prim算法以及Kruskal算法的证明

最⼩⽣成树的Prim算法以及Kruskal算法的证明Prime算法的思路:从任何⼀个顶点开始,将这个顶点作为最⼩⽣成树的⼦树,通过逐步为该⼦树添加边直到所有的顶点都在树中为⽌。

其中添加边的策略是每次选择外界到该⼦树的最短的边添加到树中(前提是⽆回路)。

Prime算法的正确性证明:引理1:对于连通图中的顶点vi,与它相连的所有边中的最短边⼀定是属于最⼩⽣成树的。

引理2:证明:假设最⼩⽣成树已经建成;(vi, vj)是连接到顶点vi的最短边,在最⼩⽣成树中取出vi,断开连接到vi的边,则⽣成树被拆分成1、顶点vi2、顶点vj所在的连通分量(单独⼀个顶点也看作⼀个独⽴的连通分量)3、其余若⼲个连通分量(个数⼤于等于0)三个部分现在要重建⽣成树,就要重新连接之前被断开的各边虽然不知道之前被断开的都是哪⼏条边,但是可以通过这样⼀个简单的策略来重建连接:将vi分别以最⼩的成本逐个连接到这若⼲个互相分离的连通分量;具体来说,就是要分别遍历顶点vi到某个连通分量中的所有顶点的连接,然后选择其中最短的边来连接vi和该连通分量;⽽要将vi连接到vj所在的连通分量,显然通过边(vi, vj)连接的成本最低,所以边(vi, vj)必然属于最⼩⽣成树(如果连接到vi的最短边不⽌⼀条,只要任意挑选其中的⼀条(vi, vj)即可,以上的证明对于这种情况同样适⽤)。

这样我们就为原来只有⼀个顶点vi的⼦树添加了⼀个新的顶点vj及新边(vi, vj);接下来只要将这棵新⼦树作为⼀个连通⼦图,并且⽤这个连通⼦图替换顶点vi重复以上的分析,迭代地为⼦树逐个地添加新顶点和新边即可。

Kruskal算法:通过从⼩到⼤遍历边集,每次尝试为最⼩⽣成树加⼊当前最短的边,加⼊成功的条件是该边不会在当前已构建的图中造成回路,当加⼊的边的数⽬达到n-1,遍历结束。

Kruskal算法的正确性证明:Kruskal算法每次为当前的图添加⼀条不会造成回路的新边,其本质是逐步地连接当前彼此分散的各个连通分量(单个顶点也算作⼀个连通分量),⽽连接的策略是每次只⽤最⼩的成本连接任意两个连通分量。

Prime算法

Prime算法
2.假设存在 Gmin使得cost(Gmin) < cost(G0) 则在 Gmin中存在 <u,v> 不属于G0
3.将<u,v>加入 G0中可得一个环,且 <u,v> 不是该环的最长边(这是因为 <u,v> ∈ Gmin)
4.这与prime每次生成最短边矛盾
5.故假设不成立,命题得证.
5. 时间复杂度
Edge* Fun(int **graph,int length){
//length个点,(length-1)条边
int* V=(int*)calloc(length,sizeof(int));
Edge* E=(Edge*)malloc((length-1)*sizeof(Edge));
//先设起始点,置1说明入队列
(3)找到AB,加入队列V=[A,D,F,B];E=[AD,DF,AB]
……
(5)找到EG,加入队列V=[A,D,F,B,E,C,G];E=[AD,DF,AB,BE,EC,EG]
//边
struct Edge{
int start;
int end;
int length;
};
//需要传入图邻接矩阵graph,点的个数length
Prime
1. 概述
普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算法又被称为DJP算法、亚尔尼克算法或普里姆-亚尔尼克算法。

最小生成树---普里姆算法(Prim算法)和克鲁斯卡尔算法(Kruskal算法)

最小生成树---普里姆算法(Prim算法)和克鲁斯卡尔算法(Kruskal算法)

最⼩⽣成树---普⾥姆算法(Prim算法)和克鲁斯卡尔算法(Kruskal算法)最⼩⽣成树的性质:MST性质(假设N=(V,{E})是⼀个连通⽹,U是顶点集V的⼀个⾮空⼦集,如果(u,v)是⼀条具有最⼩权值的边,其中u属于U,v属于V-U,则必定存在⼀颗包含边(u,v)的最⼩⽣成树)普⾥姆算法(Prim算法)思路:以点为⽬标构建最⼩⽣成树1.将初始点顶点u加⼊U中,初始化集合V-U中各顶点到初始顶点u的权值;2.根据最⼩⽣成树的定义:从n个顶点中,找出 n - 1条连线,使得各边权值最⼩。

循环n-1次如下操作:(1)从数组lowcost[k]中找到vk到集合U的最⼩权值边,并从数组arjvex[k] = j中找到该边在集合U中的顶点下标(2)打印此边,并将vk加⼊U中。

(3)通过查找邻接矩阵Vk⾏的各个权值,即vk点到V-U中各顶点的权值,与lowcost的对应值进⾏⽐较,若更⼩则更新lowcost,并将k存⼊arjvex数组中以下图为例#include<bits/stdc++.h>using namespace std;#define MAXVEX 100#define INF 65535typedef char VertexType;typedef int EdgeType;typedef struct {VertexType vexs[MAXVEX];EdgeType arc[MAXVEX][MAXVEX];int numVertexes, numEdges;}MGraph;void CreateMGraph(MGraph *G) {int m, n, w; //vm-vn的权重wscanf("%d %d", &G->numVertexes, &G->numEdges);for(int i = 0; i < G->numVertexes; i++) {getchar();scanf("%c", &G->vexs[i]);}for(int i = 0; i < G->numVertexes; i++) {for(int j = 0; j < G->numVertexes; j++) {if(i == j) G->arc[i][j] = 0;else G->arc[i][j] = INF;}}for(int k = 0; k < G->numEdges; k++) {scanf("%d %d %d", &m, &n, &w);G->arc[m][n] = w;G->arc[n][m] = G->arc[m][n];}}void MiniSpanTree_Prim(MGraph G) {int min, j, k;int arjvex[MAXVEX]; //最⼩边在 U集合中的那个顶点的下标int lowcost[MAXVEX]; // 最⼩边上的权值//初始化,从点 V0开始找最⼩⽣成树Tarjvex[0] = 0; //arjvex[i] = j表⽰ V-U中集合中的 Vi点的最⼩边在U集合中的点为 Vjlowcost[0] = 0; //lowcost[i] = 0表⽰将点Vi纳⼊集合 U ,lowcost[i] = w表⽰ V-U中 Vi点到 U的最⼩权值for(int i = 1; i < G.numVertexes; i++) {lowcost[i] = G.arc[0][i];arjvex[i] = 0;}//根据最⼩⽣成树的定义:从n个顶点中,找出 n - 1条连线,使得各边权值最⼩for(int i = 1; i < G.numVertexes; i++) {min = INF, j = 1, k = 0;//寻找 V-U到 U的最⼩权值minfor(j; j < G.numVertexes; j++) {// lowcost[j] != 0保证顶点在 V-U中,⽤k记录此时的最⼩权值边在 V-U中顶点的下标if(lowcost[j] != 0 && lowcost[j] < min) {min = lowcost[j];k = j;}}}printf("V[%d]-V[%d] weight = %d\n", arjvex[k], k, min);lowcost[k] = 0; //表⽰将Vk纳⼊ U//查找邻接矩阵Vk⾏的各个权值,与lowcost的对应值进⾏⽐较,若更⼩则更新lowcost,并将k存⼊arjvex数组中for(int i = 1; i < G.numVertexes; i++) {if(lowcost[i] != 0 && G.arc[k][i] < lowcost[i]) {lowcost[i] = G.arc[k][i];arjvex[i] = k;}}}int main() {MGraph *G = (MGraph *)malloc(sizeof(MGraph));CreateMGraph(G);MiniSpanTree_Prim(*G);}/*input:4 5abcd0 1 20 2 20 3 71 2 42 3 8output:V[0]-V[1] weight = 2V[0]-V[2] weight = 2V[0]-V[3] weight = 7最⼩总权值: 11*/时间复杂度O(n^2)克鲁斯卡尔算法(Kruskal算法)思路:以边为⽬标进⾏构建最⼩⽣成树在边集中依次寻找最⼩权值边,若构建是不形成环路(利⽤parent数组记录各点的连通分量),则将其添加到最⼩⽣成树中。

普里姆算法—Prim算法

普里姆算法—Prim算法

普⾥姆算法—Prim算法普⾥姆算法—Prim算法算法思路:⾸先就是从图中的⼀个起点a开始,把a加⼊U集合,然后,寻找从与a有关联的边中,权重最⼩的那条边并且该边的终点b在顶点集合:(V-U)中,我们也把b加⼊到集合U中,并且输出边(a,b)的信息,这样我们的集合U就有:{a,b},然后,我们寻找与a关联和b关联的边中,权重最⼩的那条边并且该边的终点在集合:(V-U)中,我们把c加⼊到集合U中,并且输出对应的那条边的信息,这样我们的集合U就有:{a,b,c}这三个元素了,⼀次类推,直到所有顶点都加⼊到了集合U。

(普⾥姆算法是允许负数的,狄杰斯特拉算法不⽀持)下⾯我们对下⾯这幅图求其最⼩⽣成树:1.假设我们从顶点v1开始,所以我们可以发现(v1,v3)边的权重最⼩,所以第⼀个输出的边就是:v1—v3=1:2.然后,我们要从v1和v3作为起点的边中寻找权重最⼩的边,⾸先了(v1,v3)已经访问过了,所以我们从其他边中寻找,发现(v3,v6)这条边最⼩,所以输出边就是:v3—-v6=43.然后,我们要从v1、v3、v6这三个点相关联的边中寻找⼀条权重最⼩的边,我们可以发现边(v6,v4)权重最⼩,所以输出边就是:v6—-v4=2.4.然后,我们就从v1、v3、v6、v4这四个顶点相关联的边中寻找权重最⼩的边,发现边(v3,v2)的权重最⼩,所以输出边:v3—–v2=55.然后,我们就从v1、v3、v6、v4,v2这2五个顶点相关联的边中寻找权重最⼩的边,发现边(v2,v5)的权重最⼩,所以输出边:v2—–v5=36.最后,我们发现六个点都已经加⼊到集合U了,我们的最⼩⽣成树建⽴完成。

Prim算法#include<stdio.h>#include<stdlib.h>#include<malloc.h>#include<string.h>#define MAX 100#define INF (~(0x1<<31))typedef struct Graph{char vexs[MAX];int vexnum;int edgnum;int matrix[MAX][MAX];} Graph,*PGraph;typedef struct EdgeData{char start;char end;int weight;} EData;static int get_position(Graph g,char ch){int i;for(i=0; i<g.vexnum; i++)if(g.vexs[i]==ch)return i;return -1;}Graph* create_graph(){char vexs[]= {'A','B','C','D','E','F','G'};int matrix[][7]={{0,12,INF,INF,INF,16,14},{12,0,10,INF,INF,7,INF},{INF,10,0,3,5,6,INF},{INF,INF,3,0,4,INF,INF},{INF,INF,5,4,0,INF,8},{16,7,6,INF,2,0,9},{14,INF,INF,INF,8,9,0}};int vlen=sizeof(vexs)/sizeof(vexs[0]);int i,j;Graph *pG;if((pG=(Graph*)malloc(sizeof(Graph)))==NULL) return NULL;memset(pG,0,sizeof(pG));pG->vexnum=vlen;for(i=0; i<pG->vexnum; i++)pG->vexs[i]=vexs[i];for(i=0; i<pG->vexnum; i++)for(j=0; j<pG->vexnum; j++)pG->matrix[i][j]=matrix[i][j];for(i=0; i<pG->vexnum; i++){for(j=0; j<pG->vexnum; j++){if(i!=j&&pG->matrix[i][j]!=INF)pG->edgnum++;}}pG->edgnum/=2;return pG;}void print_graph(Graph G){int i,j;printf("Matrix Graph: \n");for(i=0; i<G.vexnum; i++){for(j=0; j<G.vexnum; j++)printf("%10d ",G.matrix[i][j]);printf("\n");}}EData* get_edges(Graph G){EData *edges;edges=(EData*)malloc(G.edgnum*sizeof(EData)); int i,j;int index=0;for(i=0; i<G.vexnum; i++){for(j=i+1; j<G.vexnum; j++){if(G.matrix[i][j]!=INF){edges[index].start=G.vexs[i];edges[index].end=G.vexs[j];edges[index].weight=G.matrix[i][j];index++;}}}return edges;}void prim(Graph G,int start){int min,i,j,k,m,n,sum;int index=0;char prim[MAX];int weight[MAX];prim[index++]=G.vexs[start];for(i=0; i<G.vexnum; i++)weight[i]=G.matrix[start][i];weight[start]=0;for(i=0; i<G.vexnum; i++){//i⽤来控制循环的次数,每次加⼊⼀个结点,但是因为start已经加⼊,所以当i为start是跳过 if(start==i)continue;j=0;k=0;min=INF;for(k=0; k<G.vexnum; k++){if(weight[k]&&weight[k]<min){min=weight[k];j=k;}}sum+=min;prim[index++]=G.vexs[j];weight[j]=0;for(k=0; k<G.vexnum; k++){if(weight[k]&&G.matrix[j][k]<weight[k])weight[k]=G.matrix[j][k];}}// 计算最⼩⽣成树的权值sum = 0;for (i = 1; i < index; i++){min = INF;// 获取prims[i]在G中的位置n = get_position(G, prim[i]);// 在vexs[0...i]中,找出到j的权值最⼩的顶点。

随机prim算法

随机prim算法

随机prim算法Prim算法是一种普遍使用的最小生成树算法,它可以在图中找到一棵树,从而使得该树中所有边的权值之和最小。

Prim算法的基本思想是从一个顶点开始,逐步扩张最小生成树,每次向树中加入一条边,使得该边连接树上的节点和未加入树中的节点,并且权值最小。

这个过程中需要不断更新已加入树中的节点和未加入树中的节点之间的距离。

Prim算法的流程如下:1.选择一个起始顶点,将其加入到最小生成树中。

2.接着,将这个顶点可以到达的所有节点,以及它们之间的边加入到一个优先队列中。

其中,边的权值为该边连接的两个顶点值的较小值。

3.从优先队列中弹出权值最小的边,判断该边连接的两个顶点是否已经在最小生成树中,如果一个顶点已经在最小生成树中,而另外一个不在,则将未加入树中的节点和该边加入到最小生成树中。

5.重复步骤3和4,直到所有的节点都在最小生成树中。

下面是一个简单的Prim算法实例,我们来看一下:```Pythonimport heapqdef prim(graph, start):mst = [] # 保存最小生成树visited = [] # 保存已经访问的节点heap = [] # 优先队列while heap:# 找到权值最小的边w, u, v = heapq.heappop(heap)if v in visited:continuevisited.append(v)mst.append((u, v, w))return mst# 测试graph = {'A': {'B': 7, 'D': 5},'B': {'A': 7, 'C': 8, 'D': 9, 'E': 7},'C': {'B': 8, 'E': 5},'D': {'A': 5, 'B': 9, 'E': 15, 'F': 6},'E': {'B': 7, 'C': 5, 'D': 15, 'F': 8, 'G': 9},'F': {'D': 6, 'E': 8, 'G': 11},'G': {'E': 9, 'F': 11}}print(prim(graph, 'A')) # 输出:[('A', 'D', 5), ('D', 'F', 6), ('F', 'E', 8), ('E', 'C', 5), ('E', 'G', 9), ('A', 'B', 7)]```在以上实例中,我们使用了Python中的heapq模块,实现了Prim算法,以求得给定图的最小生成树。

prim算法c语言

prim算法c语言

prim算法c语言什么是Prim算法?Prim算法,也叫普里姆算法,是一种用于求解最小生成树的贪心算法。

最小生成树是指在一个无向连通图中,连接所有节点且边权值之和最小的树。

Prim算法的基本思想是从一个起始节点开始,每次选择与当前已经构建好的部分形成的子图相连的、权值最小的边所连接的节点,并将该节点加入到已经构建好的部分中。

直到所有节点都被加入到已经构建好的部分中,此时得到了一棵最小生成树。

Prim算法步骤1. 选定一个起点作为已经构建好的部分。

2. 将与该起点相连且未被访问过的边加入到候选集合中。

3. 从候选集合中选择一条权值最小的边连接到未被访问过的节点,并将该节点加入到已经构建好的部分中。

4. 将新加入节点所连接且未被访问过的边加入到候选集合中。

5. 重复步骤3和步骤4,直至所有节点都被加入到已经构建好的部分中。

Prim算法C语言实现下面给出Prim算法C语言实现代码:```#include <stdio.h>#include <stdlib.h>#include <limits.h>#define MAX_VERTICES 100#define INF INT_MAXtypedef struct {int weight;int visited;} Vertex;typedef struct {int vertices[MAX_VERTICES][MAX_VERTICES]; int num_vertices;} Graph;void init_graph(Graph *graph, int num_vertices) {graph->num_vertices = num_vertices;for (int i = 0; i < num_vertices; i++) {for (int j = 0; j < num_vertices; j++) {graph->vertices[i][j] = INF;}}}void add_edge(Graph *graph, int u, int v, int weight) { graph->vertices[u][v] = weight;graph->vertices[v][u] = weight;}void prim(Graph *graph) {Vertex vertices[MAX_VERTICES];for (int i = 0; i < graph->num_vertices; i++) {vertices[i].weight = INF;vertices[i].visited = 0;}vertices[0].weight = 0;for (int i = 0; i < graph->num_vertices - 1; i++) {// 找到未访问过的权值最小的节点int min_vertex_index = -1;for (int j = 0; j < graph->num_vertices; j++) {if (!vertices[j].visited && (min_vertex_index == -1 || vertices[j].weight < vertices[min_vertex_index].weight)) { min_vertex_index = j;}}// 将该节点标记为已访问vertices[min_vertex_index].visited = 1;// 更新与该节点相连的未访问过的节点的权值for (int j = 0; j < graph->num_vertices; j++) {if (!vertices[j].visited && graph->vertices[min_vertex_index][j] < vertices[j].weight) {vertices[j].weight = graph->vertices[min_vertex_index][j];}}}// 输出最小生成树printf("Minimum Spanning Tree:\n");for (int i = 1; i < graph->num_vertices; i++) {printf("%d - %d (%d)\n", i, (i - 1), vertices[i].weight); }}int main() {Graph graph;init_graph(&graph, 6);add_edge(&graph, 0, 1, 6);add_edge(&graph, 0, 2, 1);add_edge(&graph, 0, 3, 5);add_edge(&graph, 1, 4, 3);add_edge(&graph, 2, 4, 5);add_edge(&graph, 2, 3, 5);add_edge(&graph, 2, 5, 4);add_edge(&graph, 3 ,5 ,2);prim(&graph);return EXIT_SUCCESS;}```代码解释- 定义了Vertex结构体,用于存储节点的权值和访问状态。

普里姆算法

普里姆算法
最小生成树 ( minimum cost spanning tree )
使用不同的遍历图的方法,可以得到不同 的生成树;从不同的顶点出发,也可能得 到不同的生成树。
按照生成树的定义,n 个顶点的连通网络 的生成树有 n 个顶点、n-1 条边。
构造最小生成树的准则 必须使用且仅使用该网络中的n-1 条边 来联结网络中的 n 个顶点; 不能使用产生回路的边; 各边上的权值的总和达到最小。
采用邻接矩阵作为图的存储表示。
28
01
01
01
10 14 16 10
10
5 6 25 6 25 6 2
25 24 18 12
25
4 22 3
43
43
原图
(a)
(b)
01
01
01
10
10
10 14 16
5 6 25 6 25 6 2
25
4 22 3
(c)
25
12 25
12
4 22 3
4 22 3
(d)
普里姆(Pபைடு நூலகம்im)算法
普里姆算法的基本思想: 从连通网络 N = { V, E }中的某一顶点 u0 出 发, 选择与它关联的具有最小权值的边 ( u0, v ), 将其顶点加入到生成树顶点集合U中。 以后每一步从一个顶点在 U 中,而另一个 顶点不在 U 中的各条边中选择权值最小的 边(u, v), 把它的顶点加入到集合 U 中。如 此继续下去, 直到网络中的所有顶点都加入 到生成树顶点集合 U 中为止。
(e) (f)

求无向图的最小生成树算法——Prim与Kruskal

求无向图的最小生成树算法——Prim与Kruskal
一.Prim算法
1.算法思想
对于图G=(V,E),用Prim算法求最小生成树T=(S,TE)的流程如下
① 初始化:设S、TE为空集,任选节点K加入S。
② 选取一条权值最小的边(X,Y),其中X∈S,且not (Y∈S) 即,选取一条权值最小的、连接着S中一点与S外一点的边。
以上操作重复|V|-1次结束。由于每次加入S的点i都在当时取到了符合流程②的边min{lowcost},而lowcost[i]=w(i,closest[i]),所以此时的最小生成树的各边就是(i,closest[i]),i∈V且not (i=x)【需要注意的是出发点x的closest[x]还是x,所以应忽略,实际取到x-1条边】。把i从1取到|V|,便得到最小生成树T的每条边。
为了比较快速地选边,我们用两个数组lowcost、closest动态地维护每一个点到S的最短距离。在某一状态下,lowcost[i]表示所有与i相连且另一端点在S中的边中的权值最小值,closest[i]表示在S中且与i相连的点中与i之间距离最小的点。显然,lowcost[i]=w(i,closest[i])。需要注意的是两个数组记录的都是边而不是路径。若i没有边直接连向S,则lowcost[i]=∞。另外,若i已在S中,则lowcost[i]=0。
lowcost[j] = w[k][j];
closest[j] = k;
} //由新加入S中的k点使某些点到S的距离缩短,所以更新各点的lowcost和close= 1; i <= n; i++)
if(i != closest[i]){
设出发点为x。初始时对于任意k∈V,closest[k]=x,lowcost[k]=w(k,x)【w(i,j)表示i、j间的距离。初始化时,若两点间没有边则w(i,j)赋为一个足够大的整数(如maxint),并且所有点到自身的距离赋为0,即w(i,i)=0】

c语言prim算法

c语言prim算法

c语言prim算法
Prim算法,又称普里姆算法,是一种用于解决最小生成树问题的经典算法。

它以图论为基础,能够在一个具有权重的连通无向图中找到一棵包含所有顶点的树,且树的权重之和最小。

算法的思路相对简单。

假设有一个无向图G,其中顶点集合为V,边集合为E。

算法从一个起始节点开始,逐步扩展生成树的规模,最终得到最小生成树。

1. 初始化:
- 创建一个空的集合T,用于存放最小生成树的边。

- 随机选择一个起始节点s,并将其加入T。

2. 重复以下步骤,直到所有顶点都加入T:
- 在图G中找到一条边e,满足e的一个端点在T中,另一个端点不在T中,并且e的权重最小。

- 将边e加入T,将其另一个端点加入T。

3. 输出最小生成树。

Prim算法的核心在于选择权重最小的边,将其加入生成树。

通过不断扩展生成树的规模,直到包含所有顶点,就能得到最小生成树。

这个算法的时间复杂度为O(V^2),其中V是顶点的数量。

在稠密图中,Prim算法的效率可能较低。

为了提高效率,可以使用最小堆等
数据结构来优化选择最小边的过程,将时间复杂度降到O(ElogV)。

Prim算法在实际应用中有着广泛的用途,如网络设计、电力传输等领域。

它能够帮助我们找到一个具有最小总成本的连接方案,从而提高资源利用效率。

Prim算法是一种解决最小生成树问题的有效算法。

通过选择权重最小的边,逐步扩展生成树的规模,最终得到一个最小总成本的树。

它的应用范围广泛,并且在实际问题中具有重要意义。

希望通过以上的介绍,能够对Prim算法有一个更深入的理解。

Prim算法和Kruskal算法

Prim算法和Kruskal算法

Prim算法和Kruskal算法Prim算法和Kruskal算法都能从连通图找出最小生成树。

区别在于Prim算法是挨个找,而Kruskal是先排序再找。

一、Prim算法:Prim算法实现的是找出一个有权重连通图中的最小生成树,即:具有最小权重且连接到所有结点的树。

(强调的是树,树是没有回路的)。

Prim算法是这样来做的:首先以一个结点作为最小生成树的初始结点,然后以迭代的方式找出与最小生成树中各结点权重最小边,并加入到最小生成树中。

加入之后如果产生回路则跳过这条边,选择下一个结点。

当所有结点都加入到最小生成树中之后,就找出了连通图中的最小生成树了。

Prim算法最小生成树查找过程:注意:若候选轻边集中的轻边不止一条,可任选其中的一条扩充到T中。

连通网的最小生成树不一定是惟一的,但它们的权相等。

【例】在上图(e)中,若选取的轻边是(2,4)而不是(2,1)时,则得到如图(h)所示的另一棵MST。

算法特点该算法的特点是当前形成的集合T始终是一棵树。

将T中U和TE分别看作红点和红边集,V-U看作蓝点集。

算法的每一步均是在连接红、蓝点集的紫边中选择一条轻边扩充进T中。

MST性质保证了此边是安全的。

T从任意的根r开始,并逐渐生长直至U=V,即T 包含了C中所有的顶点为止。

MST性质确保此时的T是G的一棵MST。

因为每次添加的边是使树中的权尽可能小,因此这是一种"贪心"的策略。

算法分析该算法的时间复杂度为O(n2)。

与图中边数无关,该算法适合于稠密图。

算法演示:/sjjg/DataStructure/DS/web/flashhtml/prim.htm二、Kruskal算法:Kruskal算法与Prim算法的不同之处在于,Kruskal在找最小生成树结点之前,需要对所有权重边做从小到大排序。

将排序好的权重边依次加入到最小生成树中,如果加入时产生回路就跳过这条边,加入下一条边。

当所有结点都加入到最小生成树中之后,就找出了最小生成树。

Prim算法及证明

Prim算法及证明

Prim算法及证明Prim算法及证明(2012-02-21 12:19:12)1、算法概述用于生成连通无向图的最小代价生成树。

2、算法步骤步骤一:树T初始状态为空;步骤二:从图中任意选取一个点加入T;步骤三:从图中找出能与T形成树的所有边,将代价最小的边加入T,形成新的树T;步骤四:检查T中边的条数;步骤五:如果条数小于n-1,返回步骤三,否则程序结束,T为最小代价生成树。

3、算法证明要证明Prim算法生成的是最小生成树,我们分两步来证明:(1)Prim算法一定能得到一个生成树;(2)该生成树具有最小代价。

证明如下:(1)Prim算法每次引入一个新边,都恰好引入一个新节点:如果少于1个,则新加入的边的两个端点已经在树中,引入新边后就会形成回路;如果多于一个,即2个,则这条边的两个端点都不在树中,这条边与原来的树就独立了,不再构成一个新的树。

由于第一步中已直接引入了一个顶点,所以只需再引入n-1条边(即n-1个顶点)即可。

假设Prim算法引入边数小于n-1,就意味着还有剩余的点与已生成的树没有相连(n个节点的连通图最小边数是n-1,少于这个数说明图不连通),且剩余的点中没有任何点可以和树中的点连通,而由于原图是连通的,所以不可能存在这种情况,因此Prim算法不可能在此之前结束。

因此Prim算法必能引入n-1条边,此时得到的树是原图的生成树。

(2)下面我们用循环不变式证明生成的树具有最小代价。

循环不变式如下:假设每次引入新的边后形成的树T包含的点集为X,X中点与点之间的所有边构成一个子图G0,则T是G0的最小代价生成树。

初始化:引入新边之前,先直接引入一个点,由于此时G0中只有一个点,因此该点就是G的最小代价生成树。

保持:令引入新边前的树是T0,点集是X0,构成的子图是G0,引入的边是e,相应的点是y;得到新的树是T1,点集是X1=X0+y,构成的子图是G1。

假设T1不是G1的最小生成树,我们必然可以在G1中其它边中找到一条边d,由于T1本身是树,d加入后形成回路,回路中有代价大于d的边,将其中之一f删掉,从而得到代价更小的树。

prime算法生成迷宫的原理

prime算法生成迷宫的原理

Prime算法生成迷宫的原理主要基于图论中的Prim算法。

该算法可以在加权连通图中搜索最小生成树,即找到一个边子集,这个子集不仅连接了所有的顶点,而且所有边的权值之和最小。

在生成迷宫的场景下,可以把墙壁视为不可走的障碍,道路视为可走的连接通道,而迷宫的入口和出口则是特定的顶点。

首先,初始地图的所有位置都被设为墙,即所有位置都是不可通的。

然后,任意选择一个墙体放入墙队列中。

接着,判断这个墙体是否可以被设置为道路。

判断依据是上下左右四个位置中只有一个位置是路。

如果是,则将该位置周围的墙加入队列,然后继续下一步;如果不是,则直接进行下一步。

在从墙队列中删除当前位置后,算法会继续搜索下一个位置,直到墙队列为空。

这时,地图上就形成了一条从入口到出口的路径,即迷宫的生成。

普里姆算法(Prim)

普里姆算法(Prim)

普⾥姆算法(Prim)概览普⾥姆算法(Prim算法),图论中的⼀种算法,可在加权连通图(带权图)⾥搜索最⼩⽣成树。

即此算法搜索到的边(Edge)⼦集所构成的树中,不但包括了连通图⾥的所有顶点(Vertex)且其所有边的权值之和最⼩。

(注:N个顶点的图中,其最⼩⽣成树的边为N-1条,且各边之和最⼩。

树的每⼀个节点(除根节点)有且只有⼀个前驱,所以,只有N-1条边。

)该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(Vojtěch Jarník)发现;并在1957年由美国计算机科学家罗伯特·普⾥姆(Robert C. Prim)独⽴发现;1959年,艾兹格·迪科斯彻再次发现了该算法。

因此,在某些场合,普⾥姆算法⼜被称为DJP算法、亚尔尼克算法或普⾥姆-亚尔尼克算法。

定义假设G=(V, {E})是连通⽹,TE是N上最⼩⽣成树中边(Edge)的集合。

V是图G的顶点的集合,E是图G的边的集合。

算法从U={u0}(u0∈V),TE={}开始。

重复执⾏下述操作:在所有u∈U,v∈V-U的边(u, v)∈E中找⼀条代价(权值)最⼩的边(u0, v0)并⼊集合TE。

同时v0并⼊U直⾄U=V为⽌。

此时TE中必有n-1条边,则T=(V, {TE})为N的最⼩⽣成树。

由算法代码中的循环嵌套可得知此算法的时间复杂度为O(n2)。

过程简述输⼊:带权连通图(⽹)G,其顶点的集合为V,边的集合为E。

初始:U={u},u为从V中任意选取顶点,作为起始点;TE={}。

操作:重复以下操作,直到U=V,即两个集合相等。

在集合E中选取权值最⼩的边(u, v),u∈U,v∈V且v∉U。

(如果存在多条满⾜前述条件,即权值相同的边,则可任意选取其中之⼀。

)将v并⼊U,将(u, v)边加⼊TE。

输出:⽤集合U和TE来描述所得到的最⼩⽣成树如何实现如上⾯的这个图G=(V, {E}),其中V={v0, v1, v2, v3, v4, v5, v6, v7, v8},E= {(v0, v1), (v0, v5), (v1, v6), (v5, v6), (v1, v8), (v1, v2), (v2, v8), (v6, v7), (v3, v6), (v4, v5), (v4, v7), (v3, v7), (v3, v4), (v3,v8), (v2, v3)}⽤邻接矩阵来表⽰该图G,得上图右边的⼀个邻接矩阵。

prim算法和kruskal算法例题

prim算法和kruskal算法例题

一、概述在图论中,prim算法和kruskal算法是两种常用的最小生成树算法。

它们分别以不同的方式来寻找给定图的最小生成树,是解决最小生成树问题的有效方法。

本文将重点介绍prim算法和kruskal算法,并通过例题分析,展示它们的应用及原理。

二、prim算法1. prim算法概述2. prim算法步骤3. 例题分析:通过一个具体图示例,展示prim算法的应用过程,详细阐述每一步的操作及思路。

4. prim算法优缺点三、kruskal算法1. kruskal算法概述2. kruskal算法步骤3. 例题分析:通过一个具体图示例,展示kruskal算法的应用过程,详细阐述每一步的操作及思路。

4. kruskal算法优缺点四、prim算法和kruskal算法的比较1. 时间复杂度2. 空间复杂度3. 适用范围4. 其他特点五、例题分析总结通过对两种算法在具体例题中的应用过程分析,总结prim算法和kruskal算法的异同点,以及在实际问题中应用时的考虑因素。

六、结论根据对prim算法和kruskal算法的介绍及例题分析,总结两种算法的特点和应用场景,为不同情况下的最小生成树问题提供参考指导。

七、参考文献列出本文所参考的相关书籍、文献或全球信息站信息,为读者进一步了解prim算法和kruskal算法提供便利。

八、附录可放置示例代码、补充说明或其他相关内容,以便读者更好地理解prim算法和kruskal算法。

由于当前训练模型对于编程题的掌握有一定限制,可以提供在Prim算法和Kruskal算法方面相关的例题解析和应用案例。

以下是一个基于图的例题及其解析。

假设有一个带权重的无向连通图G,图中的顶点集合为V,边的集合为E,每条边的权重由权重函数w(u, v)给出,其中u, v为边的两个顶点。

现在需要使用Prim算法和Kruskal算法来寻找图G的最小生成树。

首先我们需要给出一个具体的图G,如下所示:顶点集合V = {A, B, C, D, E}边的集合E = {(A, B, 3), (A, C, 1), (A, D, 5), (B, C, 4), (B, D, 6), (B, E, 2), (C, D, 7), (C, E, 8), (D, E, 9)}其中,每个元组表示一条边的起始顶点、终止顶点和权重。

数据结构(三十三)最小生成树(Prim、Kruskal)

数据结构(三十三)最小生成树(Prim、Kruskal)

数据结构(三⼗三)最⼩⽣成树(Prim、Kruskal) ⼀、最⼩⽣成树的定义 ⼀个连通图的⽣成树是⼀个极⼩的连通⼦图,它含有图中全部的顶点,但只有⾜以构成⼀棵树的n-1条边。

在⼀个⽹的所有⽣成树中,权值总和最⼩的⽣成树称为最⼩代价⽣成树(Minimum Cost Spanning Tree),简称为最⼩⽣成树。

构造最⼩⽣成树的准则有以下3条:只能使⽤该图中的边构造最⼩⽣成树当且仅当使⽤n-1条边来连接图中的n个顶点不能使⽤产⽣回路的边 对⽐两个算法,Kruskal算法主要是针对边来展开,边数少时效率会⾮常⾼,所以对于稀疏图有很⼤的优势;⽽Prim算法对于稠密图,即边数⾮常多的情况会更好⼀些。

⼆、普⾥姆(Prim)算法 1.Prim算法描述 假设N={V,{E}}是连通⽹,TE是N上最⼩⽣成树中边的集合。

算法从U={u0,u0属于V},TE={}开始。

重复执⾏下⾯的操作:在所有u属于U,v 属于V-U的边(u,v)中找⼀条代价最⼩的边(u0,v0)并加⼊集合TE,同时v0加⼊U,直到U=V为⽌。

此时TE中必有n-1条边,则T=(V,{TE})为N的最⼩⽣成树。

2.Prim算法的C语⾔代码实现/* Prim算法⽣成最⼩⽣成树 */void MiniSpanTree_Prim(MGraph G){int min, i, j, k;int adjvex[MAXVEX]; /* 保存相关顶点下标 */int lowcost[MAXVEX]; /* 保存相关顶点间边的权值 */lowcost[0] = 0;/* 初始化第⼀个权值为0,即v0加⼊⽣成树 *//* lowcost的值为0,在这⾥就是此下标的顶点已经加⼊⽣成树 */adjvex[0] = 0; /* 初始化第⼀个顶点下标为0 */for(i = 1; i < G.numVertexes; i++) /* 循环除下标为0外的全部顶点 */{lowcost[i] = G.arc[0][i]; /* 将v0顶点与之有边的权值存⼊数组 */adjvex[i] = 0; /* 初始化都为v0的下标 */}for(i = 1; i < G.numVertexes; i++){min = INFINITY; /* 初始化最⼩权值为∞, *//* 通常设置为不可能的⼤数字如32767、65535等 */j = 1;k = 0;while(j < G.numVertexes) /* 循环全部顶点 */{if(lowcost[j]!=0 && lowcost[j] < min)/* 如果权值不为0且权值⼩于min */{min = lowcost[j]; /* 则让当前权值成为最⼩值 */k = j; /* 将当前最⼩值的下标存⼊k */}j++;}printf("(%d, %d)\n", adjvex[k], k);/* 打印当前顶点边中权值最⼩的边 */lowcost[k] = 0;/* 将当前顶点的权值设置为0,表⽰此顶点已经完成任务 */for(j = 1; j < G.numVertexes; j++) /* 循环所有顶点 */{if(lowcost[j]!=0 && G.arc[k][j] < lowcost[j]){/* 如果下标为k顶点各边权值⼩于此前这些顶点未被加⼊⽣成树权值 */lowcost[j] = G.arc[k][j];/* 将较⼩的权值存⼊lowcost相应位置 */adjvex[j] = k; /* 将下标为k的顶点存⼊adjvex */}}}}Prim算法 3.Prim算法的Java语⾔代码实现package bigjun.iplab.adjacencyMatrix;/*** 最⼩⽣成树之Prim算法*/public class MiniSpanTree_Prim {int lowCost; // 顶点对应的权值public CloseEdge(Object adjVex, int lowCost) {this.adjVex = adjVex;this.lowCost = lowCost;}}private static int getMinMum(CloseEdge[] closeEdges) {int min = Integer.MAX_VALUE; // 初始化最⼩权值为正⽆穷int v = -1; // 顶点数组下标for (int i = 0; i < closeEdges.length; i++) { // 遍历权值数组,找到最⼩的权值以及对应的顶点数组的下标if (closeEdges[i].lowCost != 0 && closeEdges[i].lowCost < min) {min = closeEdges[i].lowCost;v = i;}}return v;}// Prim算法构造图G的以u为起始点的最⼩⽣成树public static void Prim(AdjacencyMatrixGraphINF G, Object u) throws Exception{// 初始化⼀个⼆维最⼩⽣成树数组minSpanTree,由于最⼩⽣成树的边是n-1,所以数组第⼀个参数是G.getVexNum() - 1,第⼆个参数表⽰边的起点和终点符号,所以是2 Object[][] minSpanTree = new Object[G.getVexNum() - 1][2];int count = 0; // 最⼩⽣成树得到的边的序号// 初始化保存相关顶点和相关顶点间边的权值的数组对象CloseEdge[] closeEdges = new CloseEdge[G.getVexNum()];int k = G.locateVex(u);for (int j = 0; j < G.getVexNum(); j++) {if (j!=k) {closeEdges[j] = new CloseEdge(u, G.getArcs()[k][j]);// 将顶点u到其他各个顶点权值写⼊数组中}}closeEdges[k] = new CloseEdge(u, 0); // 加⼊u到⾃⾝的权值0for (int i = 1; i < G.getVexNum(); i++) { // 注意,这⾥从1开始,k = getMinMum(closeEdges); // 获取u到数组下标为k的顶点的权值最短minSpanTree[count][0] = closeEdges[k].adjVex; // 最⼩⽣成树第⼀个值为uminSpanTree[count][1] = G.getVexs()[k]; // 最⼩⽣成树第⼆个值为k对应的顶点count++;closeEdges[k].lowCost = 0; // 下标为k的顶点不参与最⼩权值的查找了for (int j = 0; j < G.getVexNum(); j++) {if (G.getArcs()[k][j] < closeEdges[j].lowCost) {closeEdges[j] = new CloseEdge(G.getVex(k), G.getArcs()[k][j]);}}}System.out.print("通过Prim算法得到的最⼩⽣成树序列为: {");for (Object[] Tree : minSpanTree) {System.out.print("(" + Tree[0].toString() + "-" + Tree[1].toString() + ")");}System.out.println("}");}} 4.举例说明Prim算法实现过程 以下图为例: 测试类:// ⼿动创建⼀个⽤于测试最⼩⽣成树算法的⽆向⽹public static AdjacencyMatrixGraphINF createUDNByYourHand_ForMiniSpanTree() {Object vexs_UDN[] = {"V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7", "V8"};int arcsNum_UDN = 15;int[][] arcs_UDN = new int[vexs_UDN.length][vexs_UDN.length];for (int i = 0; i < vexs_UDN.length; i++) // 构造⽆向图邻接矩阵for (int j = 0; j < vexs_UDN.length; j++)if (i==j) {arcs_UDN[i][j]=0;} else {arcs_UDN[i][j] = arcs_UDN[i][j] = INFINITY;}arcs_UDN[0][5] = 11;arcs_UDN[1][2] = 18;arcs_UDN[1][6] = 16;arcs_UDN[1][8] = 12;arcs_UDN[2][3] = 22;arcs_UDN[2][8] = 8;arcs_UDN[3][4] = 20;arcs_UDN[3][6] = 24;arcs_UDN[3][7] = 16;arcs_UDN[3][8] = 21;arcs_UDN[4][5] = 26;arcs_UDN[4][7] = 7;arcs_UDN[5][6] = 17;arcs_UDN[6][7] = 19;for (int i = 0; i < vexs_UDN.length; i++) // 构造⽆向图邻接矩阵for (int j = i; j < vexs_UDN.length; j++)arcs_UDN[j][i] = arcs_UDN[i][j];return new AdjMatGraph(GraphKind.UDN, vexs_UDN.length, arcsNum_UDN, vexs_UDN, arcs_UDN);}public static void main(String[] args) throws Exception {AdjMatGraph UDN_Graph = (AdjMatGraph) createUDNByYourHand_ForMiniSpanTree();MiniSpanTree_Prim.Prim(UDN_Graph, "V0");} 输出为:通过Prim算法得到的最⼩⽣成树序列为: {(V0-V1)(V0-V5)(V1-V8)(V8-V2)(V1-V6)(V6-V7)(V7-V4)(V7-V3)} 分析算法执⾏过程:从V0开始:-count为0,k为0,closeEdges数组的-lowCost为{0 10 INF INF INF 11 INF INF INF},adjVex数组为{V0,V0,V0,V0,V0,V0,V0,V0,V0}-⽐较lowCost,于是k为1,adjVex[1]为V0,minSpanTree[0]为(V0,V1),lowCost为{0 0 INF INF INF 11 INF INF INF}-k为1,与V1的权值⾏⽐较,得到新的-lowCost为:{0 0 18 INF INF 11 16 INF 12},adjVex数组为{V0,V0,V1,V0,V0,V0,V1,V0,V1}-⽐较lowCost,于是k为5,adjVex[5]为V0,minSpanTree[1]为(V0,V5),lowCost为{0 0 18 INF INF 0 16 INF 12}-k为5,与V5的权值⾏⽐较,得到新的-lowCost为{0 0 18 INF 26 0 16 INF 12},adjVex数组为{V0,V0,V1,V0,V5,V0,V1,V0,V1}-⽐较lowCost,于是k为8,adjVex[8]为V1,minSpanTree[2]为(V1,V8),lowCost为{0 0 18 INF INF 0 16 INF 0}... 三、克鲁斯卡尔(Kruskal)算法 1.Kruskal算法描述 Kruskal算法是根据边的权值递增的⽅式,依次找出权值最⼩的边建⽴的最⼩⽣成树,并且规定每次新增的边,不能造成⽣成树有回路,直到找到n-1条边为⽌。

Prim算法和Kruskal算法介绍

Prim算法和Kruskal算法介绍

Prim算法和Kruskal算法介绍⼀、Prim算法普利姆(Prim)算法适⽤于求解⽆向图中的(Minimum Cost Spanning Tree)。

下⾯是Prim算法构造最⼩⽣成树的过程图解。

选择⼀个节点开始,⽐如V1进⼊集合U,剩下的集合的V-U包括剩下的节点,然后寻找从集合U到集合V-U最近的路径。

这⾥有三条路径分别是权重为6到V2,权重为5到V4以及权重为1到V3,显然到通过V3连接⽽集合U和集合V-U是最近的,选择V3进⼊集合U。

同样继续选择到V-U的路径,此时有6条可选路径,分别是权为6到V2【从V1】,权为5到V4【从V1】,权为5到V2【从V3】,权为5到V4【从V3】,权为6到V5【从V3】,权为4到V6【从V3】。

选择出从V3到V6的路径并将V6添加⾄集合U中。

按照这种⽅法依次将V4,V2和V5添加到集合U直到U和全体节点结合V相等,或者说V-U集合为空时结束,这时选出的n-1条边即为最⼩⽣成树。

⼆、Kruskal算法克鲁斯卡尔(Kruskal)算法是另⼀种求解最⼩⽣成树的算法。

下⾯是Kruskal算法构造最⼩⽣成树的过程图解。

Kruskal则是采取另⼀种思路,即从边⼊⼿。

⾸先n个顶点分别视为n个连通分量,然后选择⼀条权重最⼩的边,如果边的两端分属于两个连通分量,就把这个边加⼊集合E,否则舍去这条边⽽选择下⼀条代价最⼩的边,依次类推,直到所有节点都在同⼀个连通分量上。

三、对⽐假设⽹中有n个节点和e条边,普利姆算法的时间复杂度是O(n^2),克鲁斯卡尔算法的时间复杂度是O(eloge),可以看出前者与⽹中的边数⽆关,⽽后者相反。

因此,普利姆算法适⽤于边稠密的⽹络⽽克鲁斯卡尔算法适⽤于求解边稀疏的⽹。

迷宫生成算法之一——prim算法python代码详解(Oneofthemazegenera。。。

迷宫生成算法之一——prim算法python代码详解(Oneofthemazegenera。。。

迷宫⽣成算法之⼀——prim算法python代码详解(Oneofthemazegenera。

之前已经介绍过了迷宫⽣成算法中的深度优先算法,这次让我来解析下迷宫⽣成之⼀的prim算法。

1. 我理解的迷宫⽣成算法之⼀的prim算法:从起点开始对图形进⾏分析,并把当前所在的格⼦和⾛过的格⼦标记为1,从起始格⼦出发,找到当前格⼦下⼀步能⾛的路径,然后随机选择⼀个能⾛的路径⾛,直到没有路径可⾛,那么就返回可以选择其他路径的单元格,继续探索可以的⽅法,直到把所有的单元格都⾛完了,迷宫就⽣成完毕。

2. 储备知识(1)row表⽰⾏,缩写是 r;col表⽰列,缩写是 c(2)每个单元格有上下左右四个的⽅向可以⾛,它们的表⽰⽅式如下图所⽰,理解:⽔平⽅向上⾏数是相同的,越往左边列数越⼩,越往右边列数越⼤。

垂直⽅向上列数是相同的,越往上⾏数越⼩,越往下⾏数越⼤。

(3)在M变量中,第三维存储的5个值得含义 (LEFT, UP, RIGHT, DOWN, CHECK_IF_VISITED),要理解代码,最好记住每个数字表⽰得⽅向,最后⼀个参数就是表⽰是否被访问过,如果被访问那么就为1,否则为03. 帮助看懂的代码(如果你觉得 print 太多,那你可以从代码来源中复制过来看会⽐较⼲净点):1import random2import numpy as np3from matplotlib import pyplot as plt4import matplotlib.cm as cm56# num_rows = int(input("Rows: ")) # number of rows7# num_cols = int(input("Columns: ")) # number of columns8 num_rows = 49 num_cols = 51011# The array M is going to hold the array information for each cell.12# The first four coordinates tell if walls exist on those sides13# and the fifth indicates if the cell has been visited in the search.14# M(LEFT, UP, RIGHT, DOWN, CHECK_IF_VISITED)15 M = np.zeros((num_rows, num_cols, 5), dtype=np.uint8)1617# The array image is going to be the output image to display18 image = np.zeros((num_rows * 10, num_cols * 10), dtype=np.uint8)1920# Set starting row and column21 r = 022 c = 023 history = [(r, c)] # The history is the stack of visited locations2425# Trace a path though the cells of the maze and open walls along the path.26# We do this with a while loop, repeating the loop until there is no history,27# which would mean we backtracked to the initial start.28 trend = []29while history:30print("==================================================")31# random choose a candidata cell from the cell set histroy32 r, c = random.choice(history)33print("r = ", r)34print("c = ", c)35 M[r, c, 4] = 1 # designate this location as visited36 history.remove((r, c))37 check = []38# If the randomly chosen cell has multiple edges39# that connect it to the existing maze,40# c ⼤于0才有左⽅向41if c > 0:42print("c > 0")43print([r, c - 1, 4], M[r, c - 1, 4])44# 等于1表⽰被访问过,找到已经被访问过的路径进⾏添加45if M[r, c - 1, 4] == 1:46 check.append('L')47# 等于0表⽰没有被访问过,那么就添加到需要访问history列表中,标记成2表⽰在history中将要被访问的,该值要与0和1不同,被访问后就会变成1。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
{
int min;
for(int i=0; i<n; i++)
if(st[i].lowcost != 0)break;
min=i;
for(i+1; i<n; i++)
if(st[i].lowcost!=0 && st[i].lowcost<st[min].lowcost)
min=i;
return min;
顶点集
数组
shortEdge
南京
上海
北京
南昌
天津
徐州
U
输出
adjvex
lowcost
0
0
0
0
0
0
{v0}
{v0,v1}
0
18
56
999
999
34
adjvex
lowcost
0
0
0
0
1
0
{v0,v1}
{v1,v4}
0
0
56
999
50
34
adjvex
lowcost
0
0
4
4
1
0
{v0,v1,v4}
{v4,v2}
k=k+3;
}
}
/**********深度优先遍历图************/
template <class DataType>
void MGraph<DataType>::DFSTraverse(int v)
{
cout<<vertex[v]<<" ";visited[v]=true;
for(int i=0; i<vertexNum; i++)
{
for(int i=0; i<vertexNum; i++)
visited[i]=false;
queue<int> Q;
cout<<vertex[v];visited[v]=true;
Q.push(v);
while(!Q.empty())
{
v=Q.front();Q.pop();
for(int i=0; i<vertexNum; i++)
{
G.shortEdge[i].adjvex=0;
G.shortEdge[i].lowcost=G.arc[0][i];
}
for(i=1; i<G.vertexNum; i++)//一共要找vertexNum-1次最短边下标
{
int k=G.MinEdge(G.shortEdge,G.vertexNum);//寻找最短边下标
}
for(i=1; i<vertexNum; i++)//一共要找vertexNum-1次最短边下标
{
int k=MinEdge(shortEdge,vertexNum);//寻找最短边下标
//打印出最短边顶点值及下标及权值
cout<<"【"<<vertex[k]<<"("<<k<<")"<<","
if(arc[j][k]<shortEdge[j].lowcost)
{
shortEdge[j].lowcost=arc[j][k];
shortEdge[j].adjvex=k;
}
}
}
/**********寻找最短边下标************/
template <class DataType>
int MGraph<DataType>::MinEdge(ShortEdgeNode st[],int n)
1).连通网U={南京}
cost={(南京,上海)18,(南京,北京)56,(南京,南昌)999,(南京,天津)999,(南京,徐州)34}
2).U={南京,上海}
cost={(南京,北京)56,(南京,南昌)999,(上海,天津)50,(南京,徐州)34}
3).U={南京,上海,天津}
cost={(天津,北京)13,(天津,南昌)63,(南京,徐州)34}
//打印出最短边顶点值及下标及权值
cout<<"【"<<G.vertex[k]<<"("<<k<<")"<<","
<<G.vertex[G.shortEdge[k].adjvex]<<"("<<G.shortEdge[k].adjvex<<")"<<"】:"<<G.shortEdge[k].lowcost<<endl;
void MGraph<DataType>::Prim()
{
shortEdge[0].lowcost=0;//将顶点0加入集合U
for(int i=1; i<vertexNum; i++)//初始化数组shortEdge
{
shortEdge[i].adjvex=0;
shortEdge[i].lowcost=arc[0][i];
}
}
}
5.结果截图
1)作为友元函数
2)作为成员函数
for(int j=0; j<vertexNum; j++)
arc[i][j]=999;
int k=0;
for(i=0; i<arcNum; i++)//依次输入每一条边及结点权重
{
arc[b[k]][b[k+1]]=b[k+2];arc[b[k+1]][b[k]]=b[k+2];//置有边标志
cout<<"第"<<i+1<<"条边"<<b[k]<<"->"<<b[k+1]<<" "<<"权值:"<<b[k+2]<<endl;
G.shortEdge[k].lowcost=0;//将顶点k加入集合U
for(int j=1; j<G.vertexNum; j++)//调整数组
if(G.arc[j][k]<G.shortEdge[j].lowcost)
{
G.shortEdge[j].lowcost=G.arc[j][k];
G.shortEdge[j].adjvex=k;
if(arc[v][i]!=999 && visited[i]==false)
DFSTraverse(i);
}
/**********广度优先遍历图************/
template <class DataType>
void MGraph<DataType>::BFSTraverse(int v)
if(arc[v][i]!=999 && visited[i]==false)
{
cout<<" "<<vertex[i];visited[i]=true;
Q.push(i);
}
}
}
/**********prim算法(成员函数)************/
template <class DataType>
1.无向网图及其邻接矩阵存储示意图
南京
上海
北京
南昌
天津
徐州
0 34 56 999 999 34
arc[ 6][6]= 34 0 58 999 50 999
56 58 0 76 13 30
999 999 76 0 63 48
999 50 13 63 0 999
34 56 999 999 34 0
2.Prim()算法构造最小生成树过程
/***********构造函数***********/
//设置的固定的值方便调试
template <class DataType>
MGraph<DataType>::MGraph()
{
vertexNum=6;arcNum=8;
char a[6][5]={"南京","上海","北京","南昌","天津","徐州"};
int b[]={0,1,14,0,2,46,0,5,21,1,4,32,2,3,37,2,5,25,3,5,25,3,4,38};
for(int i=0; i<vertexNum; i++)
{
strcpy(vertex[i],a[i]);
visited[i]=false;
}
for(i=0; i<vertexNum; i++)//初始化
<<vertex[shortEdge[k].adjvex]<<"("<<shortEdge[k].adjvex<<")"<<"】:"<<shortEdge[k].lowcost<<endl;
相关文档
最新文档