목차
연결된 그래프의 스패닝 트리는 그래프의 모든 정점을 포함하지만 트리를 형성하기에 충분한 n-1개의 가장자리만 포함하는 최소 연결 하위 그래프입니다. 연결된 네트워크의 모든 스패닝 트리 중에서 사이드 비용의 합이 가장 작은 스패닝 트리 를 연결된 네트워크의 최소 비용 스패닝 트리(MST) 또는 줄여서 최소 라고 합니다 . 연결된 네트워크의 최소 비용 스패닝 트리는 Prim 알고리즘 과 Kruskal 알고리즘을 사용
하여 생성할 수 있습니다.
1. 프라임 알고리즘
1.1 구현 단계
기본 단계 :
N=(V,{E})가 연결된 네트워크라고 가정하면 TE는 최소 비용 스패닝 트리의 에지 집합입니다.
① 초기 U={u0}(u0∈V), TE=공집합
② 모든 u∈U, v∈VU 에지 중에서 비용이 가장 적은 에지(u0, v0)를 선택하여 집합 TE에 병합, 그리고 동시에 v0을 병합합니다. U를 입력합니다.
③ U=V가 될 때까지 ②를 반복합니다.
즉, 특정 정점의 가중치가 가장 작은 에지를 매번 선택한다.
예 :
1.2 완전한 구현 코드 + 주석
# include<stdio.h>
# define MAX_VERTEX_NUM 20 //最多顶点个数
# define INFINITY 32768
/*图的邻接矩阵存储结构*/
typedef char VertexData;
typedef struct {
VertexData vertex[MAX_VERTEX_NUM]; //顶点向量
int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //邻接矩阵
int vexnum, arcnum; //图的顶点数和弧数
}AdjMatrix;
AdjMatrix G;
/*求顶点位置函数*/
int LocateVertex(AdjMatrix* G, VertexData v) {
int k;
for (k = 0; k < G->vexnum; k++) {
if (G->vertex[k] == v)
break;
}
return k;
}
/*创建一个无向网*/
void CreateAdjMatrix(AdjMatrix* G) {
int i, j, k, weight;
VertexData v1, v2;
printf("请输入图的顶点数和弧数:");
scanf("%d%d", &G->vexnum, &G->arcnum); //输入图的顶点数和弧数
for (i = 0; i < G->vexnum; i++) {
//初始化邻接
for (j = 0; j < G->vexnum; j++)
G->arcs[i][j] = INFINITY;
}
printf("请输入图的顶点:");
for (i = 0; i < G->vexnum; i++)
scanf(" %c", &G->vertex[i]); //输入图的顶点
for (k = 0; k < G->arcnum; k++) {
printf("请输入第%d条弧的两个顶点和权值:", k + 1);
scanf(" %c %c %d", &v1, &v2, &weight); //输入一条弧的两个顶点和权值
i = LocateVertex(G, v1);
j = LocateVertex(G, v2);
G->arcs[i][j] = G->arcs[j][i] = weight; //建立对称弧
}
}
/*普利姆算法*/
void Prime(AdjMatrix G) {
int min, i, j, k, mincost = 0;
int adjvex[MAX_VERTEX_NUM]; //保存相关顶点下标
int lowcost[MAX_VERTEX_NUM]; //保存相关顶点间边的权值
lowcost[0] = 0; //初始化第一个权值为0,即v0加入生成树
adjvex[0] = 0; //初始化第一个顶点下标为0
for (i = 1; i < G.vexnum; i++) {
//循环除下标为0外的全部顶点
lowcost[i] = G.arcs[0][i]; //将v0顶点与之有边的权值存入数组
adjvex[i] = 0; //初始化都为v0下标
}
for (i = 1; i < G.vexnum; i++) {
min = INFINITY; //初始化最小权值为无穷大
j = 1;
k = 0;
while (j < G.vexnum) {
if (lowcost[j] != 0 && lowcost[j] < min) {
//如果权值不为0,且权值小于min
min = lowcost[j]; //则让当前权值成为最小值
k = j; //将当前最小值的下标存入k
}
j++;
}
printf("(%c,%c)", G.vertex[adjvex[k]], G.vertex[k]); //打印当前顶点边中权值最小边
lowcost[k] = 0; //将当前顶点的权值设置为0,表示此顶点已经完成任务
mincost += min;
for (j = 1; j < G.vexnum; j++) {
//循环所有顶点
if (lowcost[j] != 0 && G.arcs[k][j] < lowcost[j]) {
lowcost[j] = G.arcs[k][j];
adjvex[j] = k; //将下标为k的顶点存入adjvex
}
}
}
printf("\n最小代价为:");
printf("%d\n", mincost);
}
int main() {
CreateAdjMatrix(&G);
printf("\n最小代价生成树为:");
Prime(G);
return 0;
}
1.3 실행 결과
2. 크루스칼 알고리즘
2.1 구현 단계
기본 단계 :
N=(V,{E})가 연결된 네트워크라고 가정하고 가중치가 작은 것부터 큰 것 순으로 N의 에지를 정렬합니다.
① n 정점을 n 세트로 취급합니다.
② 가중치가 작은 것부터 큰 것 순으로 에지를 선택하고, 선택한 에지는 두 정점이 같은 정점 집합 에 속하지 않는 것을 만족하고 스패닝 트리 에지 집합 에 넣고 동시에 두 정점이 만나는 정점 모서리의 꼭지점은 병합된 컬렉션에 있습니다.
③ 모든 정점이 같은 정점 집합에 속할 때까지 ②를 반복합니다.
예 :
① 가중치의 오름차순으로 선택하고자 하는 모서리를 정렬하여 (B,C), 5; (B,D), 6; (C,D), 6; (B,F), 11; (D,F), 14, (A,B), 16, (D,E), 18, (A,E), 19, (A,F), 21, (E,F), 33.
정점 수집 상태: {A}, {B}, {C}, {D}, {E}, {F}.
최소 스패닝 트리의 에지 세트: { }.
② 선택하고자 하는 에지 중에서 가중치가 가장 작은 에지를 선택한다: (B,C), 5.
정점 세트 상태는 {A}, {B,C}, {D}, {E}, {F}가 됩니다.
최소 스패닝 트리의 에지 세트: {(B,C)}.
③ 선택하고자 하는 에지 중에서 가중치가 가장 작은 에지를 선택한다: (B,D), 6.
정점 세트 상태는 {A}, {B,C,D}, {E}, {F}가 됩니다.
최소 신장 트리의 가장자리 집합: {(B,C), (B,D)}.
④ 선택할 에지(C, D), 6 중 가중치가 가장 작은 에지를 선택합니다. C, D는 동일한 정점 집합 {B, C, D}에 있으므로 포기하고 a를 다시 선택합니다. 가장 작은 변을 선택할 가장자리의 가중치: (B,F), 11.
정점 세트 상태는 {A}, {B,C,D,F}, {E}가 됩니다.
최소 신장 트리의 가장자리 집합: {(B,C), (B,D), (B,F)}.
⑤ 선택할 에지 중에서 가중치가 가장 작은 에지를 선택: (D, F), 14, D, F는 동일한 정점 집합 {B, C, D, F}에 있으므로 포기하고 다시 선택 선택할 가장자리 중 가중치가 가장 작은 가장자리: (A,B), 16.
정점 집합의 상태는 {A,B,C,D,F}, {E}가 됩니다.
최소 신장 트리의 가장자리 집합: {(B,C), (B,D), (B,F), (A,B)}.
⑥ 선택하고자 하는 Edge 중 가중치가 가장 작은 Edge를 선택한다: (D, E), 18.
정점 세트 상태는 {A,B,C,D,F,E}가 됩니다.
최소 신장 트리의 가장자리 집합: {(B,C), (B,D), (B,F), (A,B), (D,E)}.
지금까지 모든 꼭지점은 동일한 꼭짓점 집합 {A, B, C, D, F, E}에 있고 알고리즘이 종료되고 최소 스패닝 트리가 구성되며 최소 비용은 5+6+11+16+18입니다. =56.
1.2 완전한 구현 코드 + 주석
# include<stdio.h>
# define MAX_VERTEX_NUM 20 //最多顶点个数
# define INFINITY 32768
typedef char VertexData;
/*边存储结构*/
typedef struct Edge {
int u;
int v;
int weight;
}Edge, EdgeVec[MAX_VERTEX_NUM];
/*图存储结构*/
typedef struct EdgeGraph {
VertexData vertex[MAX_VERTEX_NUM]; //顶点数组存储顶点信息
EdgeVec arcs; //弧数组存储弧信息
int vexnum, arcnum; //顶点数,弧数
}EdgeGraph;
/*求顶点位置函数*/
int LocateVertex(EdgeGraph* G, VertexData v) {
int k;
for (k = 0; k < G->vexnum; k++) {
if (G->vertex[k] == v)
break;
}
return k;
}
/*创建一个网*/
void Create(EdgeGraph* G) {
int i, j, k, weight;
VertexData v1, v2;
printf("请输入图的顶点数和弧数:");
scanf("%d%d", &G->vexnum, &G->arcnum); //输入图的顶点数和弧数
for (i = 0; i < G->vexnum; i++) //初始化弧的权值
G->arcs[i].weight = INFINITY;
printf("请输入图的顶点:");
for (i = 0; i < G->vexnum; i++)
scanf(" %c", &G->vertex[i]); //输入图的顶点
for (k = 0; k < G->arcnum; k++) {
printf("请输入第%d条弧的两个顶点和权值:", k + 1);
scanf(" %c %c %d", &v1, &v2, &weight); //输入一条弧的两个顶点和权值
i = LocateVertex(G, v1);
j = LocateVertex(G, v2);
G->arcs[k].u = v1; //建立弧
G->arcs[k].v = v2;
G->arcs[k].weight = weight;
}
}
/*按权值将边从小到大排序*/
void Sort(EdgeGraph* G) {
int i, j;
Edge temp;
for (i = 0; i < G->arcnum - 1; i++) {
for (j = 0; j < G->arcnum - i - 1; j++) {
if (G->arcs[j].weight > G->arcs[j + 1].weight) {
temp = G->arcs[j];
G->arcs[j] = G->arcs[j + 1];
G->arcs[j + 1] = temp;
}
}
}
}
/*克鲁斯卡尔算法*/
void Kruskal(EdgeGraph G) {
int i, mincost = 0;
Sort(&G); //对边进行按权值排序
int Vexset[MAX_VERTEX_NUM]; //Vexset数组用于记录顶点集合,下标对应顶点序号,值对应顶点集合序号
for (i = 0; i < G.vexnum; i++) //初始化,各顶点均处于单独的顶点集合中
Vexset[i] = i;
int v1, v2, vs1, vs2;
for (int i = 0; i < G.arcnum - 1; i++){
v1 = LocateVertex(&G, G.arcs[i].u); //弧连接的顶点的序号
v2 = LocateVertex(&G, G.arcs[i].v);
vs1 = Vexset[v1]; //顶点所在顶点集合
vs2 = Vexset[v2];
if (vs1 != vs2){
//判断两个顶点不在同一顶点集合中
printf("(%c,%c)", G.arcs[i].u, G.arcs[i].v);
mincost += G.arcs[i].weight;
for (int j = 0; j < G.vexnum; j++){
if (Vexset[j] == vs2) //合并顶点集合
Vexset[j] = vs1;
}
}
}
printf("\n最小代价为:");
printf("%d\n", mincost);
}
int main() {
EdgeGraph G;
Create(&G);
printf("\n最小代价生成树为:");
Kruskal(G);
return 0;
}
1.3 실행 결과
참조: Geng Guohua "데이터 구조 - C 언어로 설명(2판)"
더 많은 데이터 구조 내용을 보려면 내 "데이터 구조" 열을 따르 십시오 .