用c语言写一个代码,可以运行的,需求如下 1.选择邻接矩阵或邻接表其中一种对图进行存储; 2.实现图的广度优先和深度优先两种遍历方法; 3.实现图的最小生成树算法,Prim或kruskal算法二者均需实现
时间: 2024-03-14 07:43:34 浏览: 77
好的,这是一个比较全面的图论算法,下面是 C 语言的实现:
```c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAX_VERTEX_NUM 20 // 图的最大顶点数
// 定义邻接矩阵结构体
typedef struct {
int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 存储边的权值
int num_vertex; // 顶点数
} MGraph;
// 定义邻接表结构体
typedef struct ArcNode {
int adjvex; // 邻接点的下标
int weight; // 权值
struct ArcNode *next; // 指向下一个邻接点的指针
} ArcNode;
typedef struct VNode {
int data; // 顶点的数据
ArcNode *first; // 指向第一个邻接点的指针
} VNode, AdjList[MAX_VERTEX_NUM];
typedef struct {
AdjList adjList;
int num_vertex; // 顶点数
} ALGraph;
// 初始化邻接矩阵
void initMGraph(MGraph *graph) {
int i, j;
printf("请输入顶点数:");
scanf("%d", &graph->num_vertex);
// 输入边的权值
printf("请输入每条边的权值:\n");
for (i = 0; i < graph->num_vertex; i++) {
for (j = 0; j < graph->num_vertex; j++) {
scanf("%d", &graph->arcs[i][j]);
}
}
}
// 初始化邻接表
void initALGraph(ALGraph *graph) {
int i, j, k, weight;
ArcNode *p;
printf("请输入顶点数:");
scanf("%d", &graph->num_vertex);
// 输入顶点的数据
printf("请输入每个顶点的数据:\n");
for (i = 0; i < graph->num_vertex; i++) {
graph->adjList[i].data = i;
graph->adjList[i].first = NULL;
}
// 输入边的权值
printf("请输入每条边的起点、终点和权值:\n");
for (k = 0; k < graph->num_vertex; k++) {
scanf("%d %d %d", &i, &j, &weight);
p = (ArcNode*)malloc(sizeof(ArcNode));
p->adjvex = j;
p->weight = weight;
p->next = graph->adjList[i].first;
graph->adjList[i].first = p;
// 无向图需加上下面这部分
p = (ArcNode*)malloc(sizeof(ArcNode));
p->adjvex = i;
p->weight = weight;
p->next = graph->adjList[j].first;
graph->adjList[j].first = p;
}
}
// 广度优先遍历
void BFS(MGraph graph, int start) {
int i, j;
bool visited[MAX_VERTEX_NUM] = {false}; // 记录每个顶点是否被访问过
int queue[MAX_VERTEX_NUM], front = 0, rear = 0; // 定义队列,front 表示队头,rear 表示队尾
printf("广度优先遍历结果:");
printf("%d ", start);
visited[start] = true;
queue[rear++] = start; // 将起点入队
while (front != rear) { // 队列不为空
i = queue[front++]; // 出队
for (j = 0; j < graph.num_vertex; j++) {
if (graph.arcs[i][j] != 0 && visited[j] == false) { // 如果 i 和 j 有边,并且 j 没有被访问过
printf("%d ", j);
visited[j] = true;
queue[rear++] = j; // 将 j 入队
}
}
}
printf("\n");
}
void BFS_AL(ALGraph graph, int start) {
int i;
bool visited[MAX_VERTEX_NUM] = {false}; // 记录每个顶点是否被访问过
int queue[MAX_VERTEX_NUM], front = 0, rear = 0; // 定义队列,front 表示队头,rear 表示队尾
ArcNode *p;
printf("广度优先遍历结果:");
printf("%d ", start);
visited[start] = true;
queue[rear++] = start; // 将起点入队
while (front != rear) { // 队列不为空
i = queue[front++]; // 出队
p = graph.adjList[i].first;
while (p != NULL) {
if (visited[p->adjvex] == false) { // 如果 j 没有被访问过
printf("%d ", p->adjvex);
visited[p->adjvex] = true;
queue[rear++] = p->adjvex; // 将 j 入队
}
p = p->next;
}
}
printf("\n");
}
// 深度优先遍历
void DFS(MGraph graph, int start, bool visited[]) {
int i;
visited[start] = true;
printf("%d ", start);
for (i = 0; i < graph.num_vertex; i++) {
if (graph.arcs[start][i] != 0 && visited[i] == false) { // 如果 start 和 i 有边,并且 i 没有被访问过
DFS(graph, i, visited);
}
}
}
void DFS_AL(ALGraph graph, int start, bool visited[]) {
ArcNode *p;
visited[start] = true;
printf("%d ", start);
p = graph.adjList[start].first;
while (p != NULL) {
if (visited[p->adjvex] == false) { // 如果 j 没有被访问过
DFS_AL(graph, p->adjvex, visited);
}
p = p->next;
}
}
// 深度优先遍历的入口函数
void DFSTraverse(MGraph graph) {
int i;
bool visited[MAX_VERTEX_NUM] = {false};
printf("深度优先遍历结果:");
for (i = 0; i < graph.num_vertex; i++) {
if (visited[i] == false) {
DFS(graph, i, visited);
}
}
printf("\n");
}
void DFSTraverse_AL(ALGraph graph) {
int i;
bool visited[MAX_VERTEX_NUM] = {false};
printf("深度优先遍历结果:");
for (i = 0; i < graph.num_vertex; i++) {
if (visited[i] == false) {
DFS_AL(graph, i, visited);
}
}
printf("\n");
}
// Prim 算法
void Prim(MGraph graph) {
int i, j, k, min, sum = 0;
int lowcost[MAX_VERTEX_NUM], closest[MAX_VERTEX_NUM];
for (i = 1; i < graph.num_vertex; i++) {
lowcost[i] = graph.arcs[0][i];
closest[i] = 0;
}
for (i = 1; i < graph.num_vertex; i++) {
min = 0x7fffffff;
for (j = 1; j < graph.num_vertex; j++) {
if (lowcost[j] != 0 && lowcost[j] < min) {
min = lowcost[j];
k = j;
}
}
printf("%d %d %d\n", closest[k], k, min);
sum += min;
lowcost[k] = 0;
for (j = 1; j < graph.num_vertex; j++) {
if (graph.arcs[k][j] != 0 && graph.arcs[k][j] < lowcost[j]) {
lowcost[j] = graph.arcs[k][j];
closest[j] = k;
}
}
}
printf("最小生成树的权值之和为:%d\n", sum);
}
// Kruskal 算法
typedef struct {
int u, v; // 两个端点的下标
int weight; // 权值
} Edge;
int cmp(const void *a, const void *b) { // 比较函数
return ((Edge*)a)->weight - ((Edge*)b)->weight;
}
int Find(int parent[], int f) { // 找父节点
if (parent[f] == f) return f;
else return parent[f] = Find(parent, parent[f]);
}
void Kruskal(MGraph graph) {
int i, j, k, sum = 0;
int parent[MAX_VERTEX_NUM];
Edge edges[MAX_VERTEX_NUM];
for (i = 0, k = 0; i < graph.num_vertex; i++) {
for (j = i + 1; j < graph.num_vertex; j++) {
if (graph.arcs[i][j] != 0) {
edges[k].u = i;
edges[k].v = j;
edges[k].weight = graph.arcs[i][j];
k++;
}
}
}
qsort(edges, k, sizeof(edges[0]), cmp); // 将边按权值从小到大排序
for (i = 0; i < graph.num_vertex; i++) {
parent[i] = i; // 初始化每个点的父节点为其本身
}
printf("最小生成树的边为:\n");
for (i = 0; i < k; i++) {
int faU = Find(parent, edges[i].u);
int faV = Find(parent, edges[i].v);
if (faU != faV) { // 如果 u 和 v 不在同一个连通块中
printf("%d %d %d\n", edges[i].u, edges[i].v, edges[i].weight);
sum += edges[i].weight;
parent[faU] = faV; // 将 u 的父节点设为 v
}
}
printf("最小生成树的权值之和为:%d\n", sum);
}
int main() {
MGraph graph_M;
ALGraph graph_AL;
int choice;
printf("请选择图的存储方式(1.邻接矩阵,2.邻接表):");
scanf("%d", &choice);
if (choice == 1) {
initMGraph(&graph_M);
BFS(graph_M, 0);
DFSTraverse(graph_M);
Prim(graph_M);
Kruskal(graph_M);
} else {
initALGraph(&graph_AL);
BFS_AL(graph_AL, 0);
DFSTraverse_AL(graph_AL);
// Prim 和 Kruskal 算法同上
}
return 0;
}
```
注意:这只是一个简单的实现,如果需要在实际项目中使用,还需要考虑更多的情况,比如错误处理、异常情况处理等。
阅读全文