Prim算法基本思想用伪代码描述如下:
算法 | Prim |
---|---|
输入 | 无向连通图G=(V,E) |
输出 | 最小生成树T=(U,TE) |
1.初始化:U={v};TE={ };
2.重复下述操作直到U=V:
2.1 在E中寻找最短边( i, j ),且满足i∈U,j∈V-U;
2.2 U = U + { j };
2.3 TE = TE + { (i , j) };
以下是Prim算法基于的存储结构
最小生成树即为:在图的所有生成树中,代价最小的树称为最小生成树。
例题:邻接矩阵为存储结构,实现的无向带权图的最小生成树算法Prim
输入:无向带权连通图
输出:深度遍历、广度遍历、最小生成树
输入:
请输入两个边顶点的序号:0 1
请输入边的权值:34
请输入两个边顶点的序号:0 2
请输入边的权值:46
请输入两个边顶点的序号:0 5
请输入边的权值:19
请输入两个边顶点的序号:1 4
请输入边的权值:12
请输入两个边顶点的序号:2 3
请输入边的权值:17
请输入两个边顶点的序号:2 5
请输入边的权值:25
请输入两个边顶点的序号:3 4
请输入边的权值:38
请输入两个边顶点的序号:3 5
请输入边的权值:25
请输入两个边顶点的序号:4 5
请输入边的权值:26
输出:
深度优先遍历序列是:ABEDCF
广度优先遍历序列是:ABCFED
最小生成树的生成过程为:
<0,5>19
<5,2>25
<2,3>17
<5,4>26
<4,1>12
示例代码:
#include <iostream>
using namespace std;
const int MaxSize = 10; //图中最多顶点个数
int visited[MaxSize]={0};
const int MAX = 1000;
struct element //改进:使用结构体数组代替lowcast数组以及adjvex数组
{
int lowcost, adjvex;
};
int MinEdge(element *e,int vertexNum);
template <class DataType>
class MGraph
{
public:
MGraph(DataType a[ ], int n, int e); //构造函数,建立具有n个顶点e条边的图
~MGraph( ) { } //析构函数为空
void DFTraverse(int v); //深度优先遍历图
void BFTraverse(int v); //广度优先遍历图
void Prim(int v) ;
private:
DataType vertex[MaxSize]; //存放图中顶点的数组
int edge[MaxSize][MaxSize]; //存放图中边的数组
int vertexNum, edgeNum; //图的顶点数和边数
};
template <class DataType>
MGraph<DataType>::MGraph(DataType a[ ], int n, int e)
{
int i, j, k ,x;
vertexNum = n;
edgeNum = e;
for (i = 0; i < vertexNum; i++)
vertex[i] = a[i];
for (i = 0; i < vertexNum; i++)
for (j = 0; j < vertexNum; j++)
edge[i][j] = MAX;
for (k = 0; k < edgeNum; k++)
{
cout << "请输入两个边顶点的序号:";
cin >> i >> j; //输入边依附的两个顶点的编号
cout << "请输入边的权值:";
cin >> x;
edge[i][j] = x; //置边的标志为1
edge[j][i] = x; //无向图 边是相通的
}
}
template <class DataType>
void MGraph<DataType>::DFTraverse(int v)
{
cout << vertex[v];
visited[v] = 1;
for (int j = 0; j < vertexNum; j++)
{
if (edge[v][j] != MAX && visited[j] == 0)DFTraverse(j); //存在与v相连的j点且j点未被访问过 则进一步遍历j点
}
}
template <class DataType>
void MGraph<DataType>::BFTraverse(int v)
{
int w, j, Q[MaxSize];
int front = -1, rear = -1;
cout << vertex[v];
visited[v] = 1;
Q[++rear] = v; //v点入队
while (front != rear)
{
w = Q[++front]; //Q出队值 w
for (j = 0; j < vertexNum; j++)//遍历所有可能与w相连的点 若有,则输出、标记、入队
{
if (edge[w][j] != MAX && visited[j] == 0)//存在与w点相连的j点且j点未被访问过 则输出j点值 然后标记j点将j点入队
{
cout << vertex[j];
visited[j] = 1;
Q[++rear] = j;
}
}
}
}
template <class DataType>
void MGraph<DataType>::Prim(int v) //从顶点v出发
{
int i,j,k;
element e[MaxSize]; //定义出发点结构体,里面包含当前出发点的所有邻点权值
for( i = 0;i<vertexNum;i++)
{
e[i].adjvex = v;
e[i].lowcost = edge[v][i];
}
e[v].lowcost = 0;
for(k = 1;k<vertexNum;k++) //迭代n-1次 因为一开始已经取了一个起点 剩下n-1个
{
j = MinEdge(e,vertexNum); //找出还未连接的点中距离目前点最近的
cout<<"<"<<e[j].adjvex<<","<<j<<">"<<e[j].lowcost<<endl; //输出j点
e[j].lowcost = 0;
for(i = 0;i<vertexNum;i++)
{
if(edge[i][j]<e[i].lowcost) //寻找j点到各个点比v到各个点路径短的,并替换
{
e[i].lowcost = edge[i][j];
e[i].adjvex = j; //j与i的距离 比v与i的距离近 因此i的最近点换成j
}
}
}
}
int MinEdge(element *e,int vertexNum)
{
int min = MAX;
int res;
for(int i = 0;i<vertexNum;i++)
{
if(e[i].lowcost!=0&&(e[i].lowcost<min))
{
res = i;
min = e[i].lowcost ;
}
}
return res;
}
int main( )
{
char ch[]={'A','B','C','D','E','F'};
MGraph<char> MG(ch, 6, 9);
for (int i=0; i<MaxSize; i++)
visited[i]=0;
cout<<"深度优先遍历序列是:";
MG.DFTraverse(0);
cout<<endl;
for (int i=0; i<MaxSize; i++)
visited[i]=0;
cout<<"广度优先遍历序列是:";
MG.BFTraverse(0);
cout<<endl;
cout<<"最小生成树的生成过程为:"<<endl;
MG.Prim(0);
cout<<endl;
system("pause");
}
此题中Prim算法构造最小生成树过程中各参数的变化如下