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);
}
1.用邻接矩阵表示无向图更方便,之后在遍历和生成最小生成树时需要不断访问2.好好理解Prim算法中的lowcost[ ]数组和adjver[ ]数组,虽然adjver[ ] 数组在Prim算法中没什么用3.Prim的主要思想映射到lowcost[ ]中就是,lowcost[ i ]相当于G.arcs[ i ][ ],随着不断地迭代,这个i值也会发生改变。当lowcost[ i ] == 0时,就意味着i这个点已经加入到了最小生成树的点集合U中。但是最坑爹的一点就是,前面你把lowcost[