在对无向图进行遍历时,若是连通图,仅需调用遍历过程(DFS和BFS)一次,从图中的任一顶点出发便可以遍历图中的各个顶点,若是非连通图,则需多次调用遍历过程,每次调用得到的顶点集连同相关的边就构成=了图的一个连通分量,设G=(V,E)为连通图,则从图中的任一顶点出发遍历图时必定将E(G)分成两个集合T和B,显然,G’=(V,T)是G的极小连通子图,即G’是G的一颗生成树,
由深度优先遍历得到的生成树称为深度优先生成树,相应的,由广度优先遍历得到的生成树称为广度优先生成树。
这样的生成树由遍历时访问过的n个顶点和遍历时经历的(n-1)条边组成
对于非连通图,每个连通分量中的顶点集和遍历时走过的边一起构成一颗生成树,各连通分量的生成树组成非连通图的生成森林。
prim算法是一种构造算法,可以求出从某一点开始的最小生成树,用于在加权连通图中找到最小生成树,这个算法可以从图的任意一个顶点开始,逐步扩展已经找到的生成树,直到所有顶点都被包含进来。
下面是prim算法实现
#include<stdio.h>
#include<stdlib.h>
#define MAXV 10
typedef struct {
int n, e;
char vexs[MAXV];
int edgs[MAXV][MAXV];
}MatGraph;
int visited[MAXV] = { 0 };
void Create(MatGraph* G)
{
int w, l, weight;
scanf("%d %d", &G->n, &G->e);
for (int i = 0; i < G->n; i++)
{
scanf("%c", &G->vexs[i]);
}
for (int i = 0; i < G->n; i++)
{
for (int j = 0; j < G->n; j++)
{
G->edgs[i][j] = 32367;
}
}
for (int i = 0; i < G->e; i++)
{
scanf("%d %d %d", &w, &l, &weight);
G->edgs[w][l] = G->edgs[l][w] = weight;
}
}
void Prim(MatGraph* G, int v)
{
int lowcost[MAXV];
int closet[MAXV];
int visited[MAXV] = { 0 };
int Min = 32367, k = 0;
for (int i = 0; i < G->n; i++)
{
lowcost[i] = G->edgs[v][i];//顶点集
closet[i] = v;//边集
}
visited[v] = 1;
/*lowcost数组用于确定下一步应该选择哪个顶点加入最小生成树,其实我个人觉得最好在写一个树组visited专门用来防止被重复访问,用这种要去比大小的就不太好
closest数组用于记录每个顶点应该如何连接到已经在最小生成树中的顶点,可以通过closet得到输出结果*/
for (int i = 1; i < G->n; i++)
{
Min = 32367; k = 0;
for (int j = 0; j < G->n; j++)
{
if (visited[j] == 0 && lowcost[j] < Min)
{
Min = lowcost[j];
k = j;
}
}
printf("%c到%c的权值为%d\n", G->vexs[closet[k]], G->vexs[k], Min);//上一个顶点,这个顶点,两边之间的权值
visited[k] = 1;
for (int j = 0; j < G->n; j++)
{
if (visited[j] == 0 && G->edgs[k][j] < lowcost[j])
{
lowcost[j] = G->edgs[k][j];
closet[j] = k;
}
}
}
}
int main()
{
MatGraph G;
Create(&G);
Prim(&G, 1);
}
这里提一下,我看有人这么写,
void Prim(MatGraph* G,int v)
{
int lowcost[MAXV];
int closet[MAXV];
int visited[MAXV] = { 0 };
int Min = 32367,k=0;
for (int i = 0; i < G->n; i++)
{
lowcost[i] = G->edgs[v][i];//顶点集
closet[i] = v;//边集
}
lowcost[v] = 0;
for (int i = 1; i < G->n; i++)
{
Min = 32367; k = 0;
for (int j = 0; j < G->n; j++)
{
if (lowcost[j] != 0 && lowcost[j] < Min)
{
Min = lowcost[j];
k = j;
}
}
printf("%c到%c的权值为%d\n", G->vexs[closet[k]], G->vexs[k], Min);//上一个顶点,这个顶点,两边之间的权值
lowcost[k]=0;
for (int j = 0; j < G->n; j++)
{
if (lowcost[j] != 0 && G->edgs[k][j] < lowcost[j])
{
lowcost[j] = G->edgs[k][j];
closet[j] = k;
}
}
}
}
这里实际是把lowcost多用了,规定lowcost等于0就是已经访问过了,这种写法有点毛病,要是有条边的权值就是0怎么办,就可能会漏掉顶点了
结果没错。