用邻接矩阵创建无向图,利用DFS、BFS完成遍历,并在此基础上利用Prim算法生成最小生成树

1.用邻接矩阵表示无向图更方便,之后在遍历和生成最小生成树时需要不断访问

2.好好理解Prim算法中的lowcost[ ]数组和adjver[ ]数组,虽然adjver[ ] 数组在Prim算法中没什么用

3.Prim的主要思想映射到lowcost[ ]中就是,lowcost[ i ]相当于G.arcs[ i ][ ],随着不断地迭代,这个i值也会发生改变。当lowcost[ i ] == 0时,就意味着i这个点已经加入到了最小生成树的点集合U中。但是最坑爹的一点就是,前面你把lowcost[ i ]置为0,后面你再去寻找最小权值的邻接点的时候,你需要遍历,用的是lowcost[i] < min这个条件。如果你没有把这个置0给排除掉,那么最后得到的结果全是0!!!所以要这样写:if (lowcost[i] < min && lowcost[i] != 0)

上代码

#include <iostream>
#include <queue>
using namespace std;

#define MaxVertexNum 100 //最大顶点数
#define MaxWeight 1000
typedef char VertexType; //假设顶点类型是字符型
typedef int ArcType; //假设边的权值是整型
typedef int Status;

typedef struct {
	VertexType vers[MaxVertexNum]; //存放顶点的数组
	ArcType arcs[MaxVertexNum][MaxVertexNum]; //邻接矩阵
	int vernum, arcnum; //要创建的图的顶点数和边数
}AMGraph; //邻接矩阵的结构体定义

Status Locate(AMGraph G, VertexType v) { //定位
	for (int i = 0; i < G.vernum; i++) {
		if (G.vers[i] == v)
			return i;
	}
	return -1;
}

void CreateUG(AMGraph& G) { //用邻接矩阵法创建一个无向图
	VertexType v1, v2;
	ArcType weight;
	cout << "请输入该无向图的总顶点数和总边数:" << endl;
	cin >> G.vernum >> G.arcnum;
	cout << "请输入顶点字符:" << endl;
	for (int i = 0; i < G.vernum; i++)
		cin >> G.vers[i]; //输入顶点的字符,完成初始化
	for (int i = 0; i < G.vernum; i++) {
		for (int j = 0; j < G.vernum; j++) {
			
				G.arcs[i][j] = MaxWeight; //初始化非对角线的权值为无穷大
		}
	}
	cout << "请输入每条边对应的顶点和权值:" << endl;
	for (int i = 0; i < G.arcnum; i++) {
		cin >> v1 >> v2 >> weight;
		int j = Locate(G, v1);
		int k = Locate(G, v2); //定位 找到v1,v2在顶点数组中的下标
		G.arcs[j][k] = weight;
		G.arcs[k][j] = weight; //无向图的邻接矩阵是对称矩阵
	}
}

void PrintUG(AMGraph G) {
	for (int i = 0; i < G.vernum; i++) {
		for (int j = 0; j < G.vernum; j++) {
			cout << G.arcs[i][j] << "\t";
		}
		cout << endl;
	}	
}

//DFS
bool Visted1[10] = { 0 };
void DFS(AMGraph G, int k) { //深度优先搜索 递归算法
	cout << G.vers[k]; Visted1[k] = true; //表示被访问过了
	for (int i = 0; i < G.vernum; i++) {
		if (G.arcs[k][i] != MaxWeight && Visted1[i] != true) {
			DFS(G, i);
		}
	}
}

//BFS 使用C++中队列的类 省去自己写队列的初始化各项操作
bool Visted2[10] = { 0 };
void BFS(AMGraph G, int k) {
	deque<int> d;
	queue<int> Q; //保存结点在数组中的序号
	cout << G.vers[k]; Visted2[k] = true;
	Q.push(k); 
	while (!Q.empty()) {
		int cur = Q.front(); //取出队首元素
		Q.pop();
		for (int i = 0; i < G.vernum; i++) {
			if (G.arcs[cur][i] != MaxWeight && Visted2[i] != true) {
				Q.push(i);
				Visted2[i] = true; //做好标记
				cout << G.vers[i]; //输出这个值
			}
		}
	}//while
}

int minEdge(int *lowcost, int n) { //求最小权值边对应的邻接点下标 !!!要去掉最开始加入到U里面那个0 不然一直返回0
	int min = MaxWeight;
	int minIndex = 0; //最小边对应结点的下标
	for (int i = 0; i < n; i++) {
		if (lowcost[i] < min && lowcost[i] != 0) { // 这个lowcost[i] != 0很关键!
			min = lowcost[i]; //更新min的值
			minIndex = i;
		}
	}//for
	return minIndex;
}

void Prim(AMGraph G, int begin) {
	int sum = 0;
	int lowcost[MaxVertexNum];
	int adjver[MaxVertexNum]; //邻接点数组
	for (int i = 0; i < G.vernum; i++) { //初始化最小权值边数组 即已经加入到最小生成树的点集合U
		lowcost[i] = G.arcs[begin][i];
		adjver[i] = begin;
	}
	//for (int i = 0; i < G.vernum; i++) cout << lowcost[i] << " " << endl;;
	lowcost[begin] = 0; //将起点加入到最小生成树顶点集里面
	for (int j = 1; j < G.vernum; j++) { //去掉顶点已经存在在U里面 所以迭代n-1次
		int minIndex = minEdge(lowcost, G.vernum);
		sum += lowcost[minIndex];
		cout << lowcost[minIndex] << " ";
		lowcost[minIndex] = 0; //将这个点加入到U中
		for (int k = 0; k < G.vernum; k++) { //调整两个数组
			if (G.arcs[minIndex][k] < lowcost[k]) {
				lowcost[k] = G.arcs[minIndex][k];
				adjver[k] = minIndex;
			}
		}//内层for
	}//外层for
	cout << "\nsum = " << sum;
}

int main() {
	AMGraph G;
	int begin; //遍历的起点
	CreateUG(G); //创建邻接矩阵类型的无向图 

	cout << "该无向图的邻接矩阵为:" << endl;
	PrintUG(G);

	cout << "请输入开始遍历的起点(第几个元素)" << endl;
	cin >> begin;

	cout << "DFS结果为:";
	DFS(G, begin - 1); //从起点v开始遍历
	cout << endl;

	cout << "BFS结果为:";
	BFS(G, begin - 1);
	cout << endl;

	cout << "Prim算法生成的最小生成树的各边权值、总权值sum分别为:" << endl;
	Prim(G, begin - 1);
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会尽力回答你的问题。 以下是用 C 语言编程实现的程序,实现了邻接矩阵表示的无向图初始化、深度优先遍历、广度优先遍历和 Prim 算法最小生成树。 ```c #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #define MAX_VERTEX_NUM 100 // 最大顶点数 #define INF 0x3f3f3f3f // 无穷大 typedef struct Graph { int vexNum; // 顶点数 int arcNum; // 边数 int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 邻接矩阵 } Graph; // 初始化无向图 void initGraph(Graph *graph) { printf("请输入顶点数和边数:\n"); scanf("%d %d", &graph->vexNum, &graph->arcNum); for (int i = 0; i < graph->vexNum; i++) { for (int j = 0; j < graph->vexNum; j++) { graph->arcs[i][j] = INF; } } printf("请输入每条边的起点、终点和权值:\n"); for (int k = 0; k < graph->arcNum; k++) { int i, j, w; scanf("%d %d %d", &i, &j, &w); graph->arcs[i][j] = w; graph->arcs[j][i] = w; } } // 深度优先遍历 void dfs(Graph *graph, int v, bool visited[]) { visited[v] = true; printf("%d ", v); for (int i = 0; i < graph->vexNum; i++) { if (graph->arcs[v][i] != INF && !visited[i]) { dfs(graph, i, visited); } } } // 广度优先遍历 void bfs(Graph *graph, int v, bool visited[]) { int queue[MAX_VERTEX_NUM], front = 0, rear = 0; visited[v] = true; queue[rear++] = v; while (front < rear) { int u = queue[front++]; printf("%d ", u); for (int i = 0; i < graph->vexNum; i++) { if (graph->arcs[u][i] != INF && !visited[i]) { visited[i] = true; queue[rear++] = i; } } } } // Prim 算法最小生成树 void prim(Graph *graph) { int lowcost[MAX_VERTEX_NUM], closest[MAX_VERTEX_NUM], mst[MAX_VERTEX_NUM]; for (int i = 0; i < graph->vexNum; i++) { lowcost[i] = graph->arcs[0][i]; closest[i] = 0; mst[i] = -1; } mst[0] = 0; for (int i = 1; i < graph->vexNum; i++) { int minCost = INF, k = -1; for (int j = 0; j < graph->vexNum; j++) { if (mst[j] == -1 && lowcost[j] < minCost) { minCost = lowcost[j]; k = j; } } if (k != -1) { mst[k] = closest[k]; printf("(%d, %d) ", mst[k], k); for (int j = 0; j < graph->vexNum; j++) { if (graph->arcs[k][j] < lowcost[j]) { lowcost[j] = graph->arcs[k][j]; closest[j] = k; } } } } } int main() { Graph graph; initGraph(&graph); printf("深度优先遍历结果:\n"); bool visited[MAX_VERTEX_NUM] = {false}; for (int i = 0; i < graph.vexNum; i++) { if (!visited[i]) { dfs(&graph, i, visited); } } printf("\n"); printf("广度优先遍历结果:\n"); for (int i = 0; i < graph.vexNum; i++) { visited[i] = false; } for (int i = 0; i < graph.vexNum; i++) { if (!visited[i]) { bfs(&graph, i, visited); } } printf("\n"); printf("最小生成树结果:\n"); prim(&graph); printf("\n"); return 0; } ``` 希望这个程序可以帮到你!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值