Prim算法又称为加边法,即每次选择最小权值的边加入到生成树中,然后再更新权值,如此反复,保证每次最优来达到最优解。特点是时刻维护一棵树,算法不断加边,加的过程始终是一棵树
节点结构
1.图的结点结构
图的顶点集
图的邻接矩阵
顶点个数
边的个数
2.结构体数组
adjvex---代表到当前下标的顶点
lowcost---代表到当前下标顶点的权值
Prim
我们把节点分为两大块;一块是最小生成树的节点,一块是尚未处理的节点
通过将shortEdge[i].lowcost的值赋为0来标识该点已加入最小生成树之中
具体过程:
先将选好的start节点的邻接矩阵的值初始化给shortEdge数组
再将start节点放在最小生成树的那一块(shortEdge[start].lowcost=0;)
再遍历剩下是节点;寻找此时shortEdge数组(在尚未处理的节点中寻找,即shortEdge[i].lowcost!=0)的最小lowcost,将该下标赋值给k
打印路径及权值
然后遍历start这个点的邻接矩阵,如果邻接矩阵的值更小,就更新shortEdge的lowcost,再更新adjvex即新的最短路的点
#include<iostream>
#include<string.h>
#define mymax 65535
using namespace std;
typedef struct Graph
{
int* spot;//点集
int** line;//邻接矩阵
int spotNum;
int lineNum;
}Graph;
Graph* initGraph(int dianshu)
{
Graph* G = new Graph;
G->spotNum = dianshu;
G->lineNum = 0;
G->spot = new int[dianshu];
G->line = new int* [dianshu];
for (int i = 0; i < dianshu; i++)
{
G->line[i] = new int[dianshu];
}
return G;
}
void createGraph(Graph* G, int* dian, int* bian)
{
for (int i = 0; i < G->spotNum; i++)
{
G->spot[i] = dian[i];
for (int j = 0; j < G->spotNum; j++)
{
G->line[i][j] = bian[j + i * G->spotNum];
if (G->line[i][j] != 0)
{
G->lineNum++;
}
}
}
G->lineNum /= 2;
}
typedef struct arry
{
int adjvex;//通过其值到当前下标顶点
int lowcost;//当前生成树到其他顶点的值
}arry;
arry* initShortEdge(int dianshu)//初始化shortEdge数组
{
arry* shortEdge = new arry[dianshu];
for (int i = 0; i < dianshu; i++)
{
shortEdge[i].adjvex = 0;
shortEdge[i].lowcost = 0;
}
return shortEdge;
}
int minEdge(arry* shortEdge, int dianshu)
{
int min = 65535;
int k;
for (int i = 0; i < dianshu; i++)
{
if (shortEdge[i].lowcost != 0 && shortEdge[i].lowcost < min)
{
min = shortEdge[i].lowcost;
k = i;
}
}
return k;
}
void outputSMT(int k, arry* shortEdge)
{
cout << "(" << shortEdge[k].adjvex << "," << k << ")" << " " << shortEdge[k].lowcost << endl;
}
void Prim(Graph* G, int start)
{
arry* shortEdge = initShortEdge(G->spotNum);
for (int i = 0; i < G->spotNum; i++)
{
shortEdge[i].lowcost = G->line[start][i];//通过start值到当前下标顶点的权值
shortEdge[i].adjvex = start;//通过start到当前下标顶点
}
shortEdge[start].lowcost = 0;//将当前start节点加入最小生成树集合中
for (int i = 0; i < G->spotNum - 1; i++)//第一个顶点不需要遍历
{
int k = minEdge(shortEdge, G->spotNum);//寻找最短边的邻接点
outputSMT(k, shortEdge);
shortEdge[k].lowcost = 0;//将顶点k加入到最小生成树
for (int j = 0; j < G->spotNum; j++)
{
if (G->line[k][j] < shortEdge[j].lowcost)
{
shortEdge[j].lowcost = G->line[k][j];
shortEdge[j].adjvex = k;
}
}
}
}
void printLine(Graph* G)
{
for (int i = 0; i < G->spotNum; i++)
{
for (int j = 0; j < G->spotNum; j++)
{
cout << G->line[i][j] << "\t";
}
cout << endl;
}
cout << endl;
}
void printSpot(Graph* G)
{
for (int i = 0; i < G->spotNum; i++)
{
cout << G->spot[i] << "\t";
}
cout << endl;
}
int main()
{
int array[] = { 0,1,2,3,4,5 };
int dianshu = sizeof(array) / sizeof(int);
Graph* G = initGraph(dianshu);
int bian[] = { 0,34,46,mymax,mymax,19,
34,0,mymax,mymax,12,mymax,
46,mymax,0,17,mymax,25,
mymax,mymax,17,0,38,25,
mymax,12,mymax,38,0,26,
19,mymax,25,25,26,0 };
createGraph(G, array, bian);
int start;
cout << "请输入从哪一个顶点出发:";
cin >> start;
cout << endl;
cout << "点集:" << endl;
printSpot(G);
cout << endl;
cout << "邻接矩阵:" << endl;
printLine(G);
cout << "路径:" << endl;
Prim(G, start);
}