本文主要是介绍Prim算法的C语言实现(邻接矩阵),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>#define MAX 100 // 矩阵最大容量
#define INF (~(0x1<<31)) // 最大值(即0X7FFFFFFF)
#define isLetter(a) ((((a)>='a')&&((a)<='z')) || (((a)>='A')&&((a)<='Z')))
#define LENGTH(a) (sizeof(a)/sizeof(a[0]))// 邻接矩阵
typedef struct _graph
{char vexs[MAX]; // 顶点集合int vexnum; // 顶点数int edgnum; // 边数int matrix[MAX][MAX]; // 邻接矩阵
}Graph, *PGraph;/*
* 返回ch在matrix矩阵中的位置
*/
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;
}/*
* 读取一个输入字符
*/
static char read_char()
{char ch;do {ch = getchar();} while (!isLetter(ch));return ch;
}/*
* 创建图(自己输入)
*/
Graph* create_graph()
{char c1, c2;int v, e;int i, j, weight, p1, p2;Graph* pG;// 输入"顶点数"和"边数"printf("input vertex number: ");scanf_s("%d", &v);printf("input edge number: ");scanf_s("%d", &e);if (v < 1 || e < 1 || (e >(v * (v - 1)))){printf("input error: invalid parameters!\n");return NULL;}if ((pG = (Graph*)malloc(sizeof(Graph))) == NULL)return NULL;memset(pG, 0, sizeof(Graph));// 初始化"顶点数"和"边数"pG->vexnum = v;pG->edgnum = e;// 初始化"顶点"for (i = 0; i < pG->vexnum; i++){printf("vertex(%d): ", i);pG->vexs[i] = read_char();}// 1. 初始化"边"的权值for (i = 0; i < pG->vexnum; i++){for (j = 0; j < pG->vexnum; j++){if (i == j)pG->matrix[i][j] = 0;elsepG->matrix[i][j] = INF;}}// 2. 初始化"边"的权值: 根据用户的输入进行初始化for (i = 0; i < pG->edgnum; i++){// 读取边的起始顶点,结束顶点,权值printf("edge(%d):", i);c1 = read_char();c2 = read_char();scanf_s("%d", &weight);p1 = get_position(*pG, c1);p2 = get_position(*pG, c2);if (p1 == -1 || p2 == -1){printf("input error: invalid edge!\n");free(pG);return NULL;}pG->matrix[p1][p2] = weight;pG->matrix[p2][p1] = weight;}return pG;
}/*
* 创建图(用已提供的矩阵)
*/
Graph* create_example_graph()
{char vexs[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };int matrix[][9] = {/*A*//*B*//*C*//*D*//*E*//*F*//*G*//*A*/{ 0, 12, INF, INF, INF, 16, 14 },/*B*/{ 12, 0, 10, INF, INF, 7, INF },/*C*/{ INF, 10, 0, 3, 5, 6, INF },/*D*/{ INF, INF, 3, 0, 4, INF, INF },/*E*/{ INF, INF, 5, 4, 0, 2, 8 },/*F*/{ 16, 7, 6, INF, 2, 0, 9 },/*G*/{ 14, INF, INF, INF, 8, 9, 0 } };int vlen = LENGTH(vexs);int i, j;Graph* pG;// 输入"顶点数"和"边数"if ((pG = (Graph*)malloc(sizeof(Graph))) == NULL)return NULL;memset(pG, 0, sizeof(Graph));// 初始化"顶点数"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;
}/*
* 返回顶点v的第一个邻接顶点的索引,失败则返回-1
*/
static int first_vertex(Graph G, int v)
{int i;if (v<0 || v>(G.vexnum - 1))return -1;for (i = 0; i < G.vexnum; i++)if (G.matrix[v][i] != 0 && G.matrix[v][i] != INF)return i;return -1;
}/*
* 返回顶点v相对于w的下一个邻接顶点的索引,失败则返回-1
*/
static int next_vertix(Graph G, int v, int w)
{int i;if (v<0 || v>(G.vexnum - 1) || w<0 || w>(G.vexnum - 1))return -1;for (i = w + 1; i < G.vexnum; i++)if (G.matrix[v][i] != 0 && G.matrix[v][i] != INF)return i;return -1;
}/*
* 深度优先搜索遍历图的递归实现
*/
static void DFS(Graph G, int i, int *visited)
{int w;visited[i] = 1;printf("%c ", G.vexs[i]);// 遍历该顶点的所有邻接顶点。若是没有访问过,那么继续往下走for (w = first_vertex(G, i); w >= 0; w = next_vertix(G, i, w)){if (!visited[w])DFS(G, w, visited);}}/*
* 深度优先搜索遍历图
*/
void DFSTraverse(Graph G)
{int i;int visited[MAX]; // 顶点访问标记// 初始化所有顶点都没有被访问for (i = 0; i < G.vexnum; i++)visited[i] = 0;printf("DFS: ");for (i = 0; i < G.vexnum; i++){//printf("\n== LOOP(%d)\n", i);if (!visited[i])DFS(G, i, visited);}printf("\n");
}/*
* 广度优先搜索(类似于树的层次遍历)
*/
void BFS(Graph G)
{int head = 0;int rear = 0;int queue[MAX]; // 辅组队列int visited[MAX]; // 顶点访问标记int i, j, k;for (i = 0; i < G.vexnum; i++)visited[i] = 0;printf("BFS: ");for (i = 0; i < G.vexnum; i++){if (!visited[i]){visited[i] = 1;printf("%c ", G.vexs[i]);queue[rear++] = i; // 入队列}while (head != rear){j = queue[head++]; // 出队列for (k = first_vertex(G, j); k >= 0; k = next_vertix(G, j, k)) //k是为访问的邻接顶点{if (!visited[k]){visited[k] = 1;printf("%c ", G.vexs[k]);queue[rear++] = k;}}}}printf("\n");
}/*
* 打印矩阵队列图
*/
void print_graph(Graph G)
{int i, j;printf("Martix Graph:\n");for (i = 0; i < G.vexnum; i++){for (j = 0; j < G.vexnum; j++)printf("%10d ", G.matrix[i][j]);printf("\n");}
}/*
* prim最小生成树
*
* 参数说明:
* G -- 邻接矩阵图
* start -- 从图中的第start个元素开始,生成最小树
*/
void prim(Graph G, int start)
{int min, i, j, k, m, n, sum;int index = 0; // prim最小树的索引,即prims数组的索引char prims[MAX]; // prim最小树的结果数组int weights[MAX]; // 顶点间边的权值// prim最小生成树中第一个数是"图中第start个顶点",因为是从start开始的。prims[index++] = G.vexs[start];// 初始化"顶点的权值数组",// 将每个顶点的权值初始化为"第start个顶点"到"该顶点"的权值。for (i = 0; i < G.vexnum; i++)weights[i] = G.matrix[start][i];// 将第start个顶点的权值初始化为0。// 可以理解为"第start个顶点到它自身的距离为0"。weights[start] = 0;for (i = 0; i < G.vexnum; i++){// 由于从start开始的,因此不需要再对第start个顶点进行处理。if (start == i)continue;j = 0;k = 0;min = INF;// 在未被加入到最小生成树的顶点中,找出权值最小的顶点。while (j < G.vexnum){// 若weights[j]=0,意味着"第j个节点已经被排序过"(或者说已经加入了最小生成树中)。if (weights[j] != 0 && weights[j] < min){min = weights[j];k = j;}j++;}// 经过上面的处理后,在未被加入到最小生成树的顶点中,权值最小的顶点是第k个顶点。// 将第k个顶点加入到最小生成树的结果数组中prims[index++] = G.vexs[k];// 将"第k个顶点的权值"标记为0,意味着第k个顶点已经排序过了(或者说已经加入了最小树结果中)。weights[k] = 0;// 当第k个顶点被加入到最小生成树的结果数组中之后,更新其它顶点的权值。for (j = 0; j < G.vexnum; j++){// 当第j个节点没有被处理,并且需要更新时才被更新。if (weights[j] != 0 && G.matrix[k][j] < weights[j])weights[j] = G.matrix[k][j];}}// 计算最小生成树的权值sum = 0;for (i = 1; i < index; i++){min = INF;// 获取prims[i]在G中的位置n = get_position(G, prims[i]);// 在vexs[0...i]中,找出到j的权值最小的顶点。for (j = 0; j < i; j++){m = get_position(G, prims[j]);if (G.matrix[m][n]<min)min = G.matrix[m][n];}sum += min;}// 打印最小生成树printf("PRIM(%c)=%d: ", G.vexs[start], sum);for (i = 0; i < index; i++)printf("%c ", prims[i]);printf("\n");
}void main()
{Graph* pG;// 自定义"图"(输入矩阵队列)//pG = create_graph();// 采用已有的"图"pG = create_example_graph();//print_graph(*pG); // 打印图//DFSTraverse(*pG); // 深度优先遍历//BFS(*pG); // 广度优先遍历prim(*pG, 0); // prim算法生成最小生成树
}
## 实验结果 ##
这篇关于Prim算法的C语言实现(邻接矩阵)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!