图的最小生成树:Prim算法实现报告

Prim算法的原理见《算法笔记》p406

下面来说说用代码怎么实现这个思路。

首先,需要准备一个数组来记录一个每个顶点是在保护罩内(true)还是在保护罩外(false)。注意,这里并不需要两个数组(一个存所有在保护罩内的顶点,一个存所有在保护罩外的顶点,这样太麻烦了)。

然后需要准备一个数组来记录所有顶点到保护罩的距离(weight),注意只要距离不是INFINETE,就说明一定能从保护罩出发到这个顶点。

Prim算法生成最小生成树的过程说白了就是一个while(1)循环

用一个临时变量pos来记录亚历山大大帝的当前的位置。

然后只需要更新pos能到所有顶点的weight就行了。(只需要更新 pos所连接的那些点就行了!因为每次循环只有这些顶点的权重可能发生变化。)

更新完weight之后,只 需要!选择不在保护罩中的 最小的weight点 走就行!即更新pos为该点.(注意不需要判断一个顶点是不和保护罩有边!因为weight!=INF 就代表一定能从保护罩走到该点)

用一个循环遍历“记录是否在保护罩”的数组就可以。设置一个temp 一个minWeight,遍历数组中所有的元素。不断更新这两个值就可以,然后pos = temp。 如果循环下来temp没变,说明当前已经无路可走了,跳出while循环即可。

代码:

这些是准备工作:可以跳过不看

// 图的基本算法与Prim算法实现.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define INF 10000

class graph {
	int verNum;
	int edgNum;
	char* ver;
	int** edg;
	map verMap;
	queue minGeneTree;
	int minTreeWeight;
	bool* isIn;
	int* verWeight;
public:
	void generate();
	void display();
	void Prim();
	void displayTree();
};
void graph::displayTree() {
	cout << "最小生成树的权重:" << minTreeWeight << endl;
	cout << "最小生成树:" << endl;
	while (!minGeneTree.empty()) {
		cout << minGeneTree.front() << endl;
		minGeneTree.pop();
	}
	return;
}
void graph::generate() {
	cout << "请输入顶点数:";
	cin >> verNum;
	cout << "请输入边数:";
	cin >> edgNum;
#if 1
	isIn = (bool*)malloc(sizeof(bool)*verNum);
	memset(isIn, 0, sizeof(bool)*verNum);
	verWeight = (int*)malloc(sizeof(int)*verNum);
	verWeight[0] = 0;
	fill(verWeight + 1, verWeight + verNum, INF);
#endif

	ver = (char*)malloc(sizeof(char)*verNum);
	memset(ver, 0, sizeof(char)*verNum);

	edg = (int**)malloc(sizeof(int*)*verNum);
	memset(edg, 0, sizeof(int*)*verNum);
	for (int i = 0; i < edgNum; i++) {
		edg[i] = (int*)malloc(sizeof(int)*verNum);
		memset(edg[i], 0, sizeof(int)*verNum);
	}
	for (int i = 0; i < verNum; i++) {
		cout << "请输入第" << i << "个顶点:";
		cin >> ver[i];
		verMap[ver[i]] = i;
	}
	for (int i = 0; i < edgNum; i++) {
		cout << "请输入第" << i << "条边 例如:a,b:";
		char buff[4] = { 0 };
		cin >> buff;
		int row = verMap[buff[0]];
		int col = verMap[buff[2]];
		cout << "请输入该边的权重:";
		int weight;
		cin >> weight;
		edg[row][col] = weight;
		edg[col][row] = weight;
	}
	return;
}
void graph::display() {
	cout << "邻接矩阵:" << endl;
	//cout << "所有顶点:" << endl;
	for (int i = 0; i < verNum; i++) {

		cout << "  " << ver[i];
	}
	cout << endl;
	//cout << "邻接矩阵:" << endl;
	for (int i = 0; i < verNum; i++) {
		cout << ver[i] << " ";
		for (int j = 0; j < verNum; j++) {
			cout << edg[i][j] << " ";
		}
		cout << endl;
	}
}



Prim算法的实现:

minTreeWeight是用来累积最小生成树的总权重的。

pos是亚历山大的位置。默认从0开始。即从第一个顶点开始生成最小生成树。

void graph::Prim() {
	minTreeWeight = 0;
	int pos = 0;
	verWeight[0] = 0;
	while (1) {
		//1.标记pos在保护罩内
		isIn[pos] = true;
		minTreeWeight += verWeight[pos];
                //2.更新pos周围顶点的权重
		for (int i = 0; i < verNum; i++) {
			if (edg[pos][i] != 0 && isIn[i] == false) {
				verWeight[i] = (edg[pos][i] < verWeight[i]) ? edg[pos][i] : verWeight[i];
			}
		}
                //3.寻找最小权重顶点
		int min = INF;
		int minpos = -1;
		for (int i = 0; i < verNum; i++) {
			if (isIn[i] == false && verWeight[i] < min) {
				minpos = i;
				min = verWeight[i];
			}
		}
                //4.如果没有找到,就跳出循环
		if (minpos == -1) return;
                //5.更新pos的位置
		pos = minpos;
                //6.以下代码可忽略,这些是用来保存路径的
		int prePos;
		for (int i = 0; i < verNum; i++) {
			if (isIn[i] == true && edg[pos][i] == min) {
				prePos = i;
			}
		}
#if 1
		char edgString[1024] = { 0 };
		sprintf(edgString, "(%c,%c)", ver[prePos], ver[pos]);
		minGeneTree.push(string(edgString));
#endif
	}
	return;
}
int main()
{
#if 0

#else if
	graph G;
	G.generate();
	G.display();
	G.Prim();
	G.displayTree();
#endif
	return 0;
}

 

你可能感兴趣的:(算法与数据结构)