Prim算法用于生成最小生成树,根据的性质为最小生成树的MST性质
MST性质:
假设G=(V,E)是一个无向联通网络,U是顶点集合V的一个非空子集,若(u,v)是一条有最小权值的边,其中u∈U,v∈V-U,则
必存在一棵包含边(u,v)的最小生成树。
Prim算法思想:
设G=(V,E)是一个无向连通图,令T=(U,TE)(U代表顶点,TE代表边)是G的最小生成树。T的初始状态为U={V0},TE={}
,然后重复以下操作:
在所有u∈U,v∈V-U的边里找一条权值最小的边(u,v)加入集合TE,同时v加入集合U,直到U=V为止,此时,TE中有n-1条边,T就是最小
生成树。
/*************************************************************************
> File Name: Graph.cpp
> Author: Shorey
> Mail: shoreybupt@gmail.com
> Created Time: 2015年04月13日 星期一 14时53分37秒
************************************************************************/
#include<iostream>
#include<stdio.h>
using namespace std;
const int MaxSize=10;//最大顶点数
const int Max=1000;//定义邻接矩阵最大值,取该值代表两点不链接
class MGraph
{
public:
MGraph(int a[], int n, int e);
~MGraph(){ }
int GetVex(int i);//获取图中第i个顶点的数据信息
void PutVex(int i, int value);//把第i个顶点的数据设置为value
// void InsertVex(int i, int value);//插入一个顶点,其编号为i值为value
// void DeleteVex(int i);//删除图中第i个顶点
void InsertArc(int i, int j,int weight);//插入边,其两个顶点编号为i和j
void DeleteArc(int i, int j);//删除边,其两个顶点编号为i和j
void Clear();//清理访问痕迹
void DFSTraverse(int v);//深度优先搜索
void BFSTraverse(int v);//广度优先搜索
friend void Prim(MGraph &G);//最小生成树的Prim算法
private:
int vertex[MaxSize]; //存放顶点数组
int arc[MaxSize][MaxSize];//存放图中的边的数组
int vertexNum,arcNum;//图中的顶点数和边数
int visited[MaxSize];//访问标记数组
};
MGraph::MGraph(int a[], int n, int e)
{
if(n>MaxSize)
{
printf("输入的顶点数过大!");
return ;
}
for(int i=0; i<MaxSize; i++) //初始化访问标记
visited[i]=0;
vertexNum = n;
arcNum = e;
for(int i=0; i<vertexNum; i++) //初始化顶点数组
vertex[i] = a[i];
for(int i=0; i<vertexNum; i++) //初始化邻接矩阵
for(int j=0; j<vertexNum; j++)
{
if(i!=j)
arc[i][j] = Max; //初始时顶点和非自身的顶点的距离权值都设为Max
else
arc[i][j] = 0; //顶点自身和自身的距离权值为0
}
for(int k=0; k<arcNum; k++) //输入边的依附顶点i,j
{
int i,j,weight;
printf("输入相互连接的两个顶点及两顶点之间的权值,回车结束一组\n");
scanf("%d%d%d",&i,&j,&weight);
arc[i][j] = weight; //修改邻接矩阵中的距离权值
arc[j][i] = weight;
}
}
void MGraph::Clear()
{
for(int i=0; i<MaxSize; i++)//清理访问标记
visited[i]=0;
}
void MGraph::DFSTraverse(int v) //深度优先搜索
{
printf("%d ",vertex[v]); //打印被访问的顶点数据
visited[v]=1;
for(int i=0; i<vertexNum; i++)
{
if(arc[v][i]!=Max&&visited[i]==0) //继续访问未被访问过的邻接节点
DFSTraverse(i);
}
}
int MGraph::GetVex(int i)
{
return vertex[i];
}
void MGraph::PutVex(int i, int value)
{
vertex[i]=value;
}
void MGraph::InsertArc(int i, int j,int weight)
{
if(i!=j)
arc[i][j]=weight;
}
void MGraph::DeleteArc(int i, int j)
{
if(i!=j)
arc[i][j]=Max;
}
void MGraph::BFSTraverse(int v)//广度优先搜索
{
int Q[MaxSize]; //初始化工作队列
int front = -1, rear = -1;
printf("%d ",vertex[v]); //打印被访问的顶点
visited[v] = 1;
Q[++rear] = v; //被访问的顶点入队
while(front!=rear)
{
v = Q[++front]; //队头元素出队
for(int j = 0; j<vertexNum; j++)
if(arc[v][j]!=Max&&visited[j]==0)//访问和出队顶点相连的顶点
{
printf("%d ",vertex[j]);
visited[j] = 1;
Q[++rear] = j;//访问的顶点入队
}
}
printf("\n");
}
int MinEdge(int weight[], int n)
{
int result = Max;
int index;
for(int i=0; i<n; i++)
if(result>weight[i]&&weight[i]!=0)
{
index = i;
result = weight[i];
}
return index;
}
void Prim(MGraph &G)//最小生成树算法Prim
{
int adjweight[G.vertexNum],adjvex[G.vertexNum];
for(int i=1; i<G.vertexNum; i++)//存储0号节点和其他节点之间的权值
{
adjweight[i] = G.arc[0][i];
adjvex[i] = 0; //设置其他顶点均和0号顶点相连的标记
}
adjweight[0] = 0; //把0号顶点加入最小生成树中
for(int i=1; i<G.vertexNum; i++)
{
int k = MinEdge(adjweight, G.vertexNum);//找到与已完成的生成树中顶点距离最短的顶点
printf("(%d,%d),%d;",k,adjvex[k],adjweight[k]);//输出即将加入生成树的结点的信息
adjweight[k] = 0;//节点k加入生成树
for(int j=1; j<G.vertexNum; j++) //更新adjweight,adjvex
{
if(k!=j&&G.arc[k][j]<adjweight[j])
{
adjweight[j] = G.arc[k][j];
adjvex[j] = k;
}
}
}
printf("\n");
}
int main()
{
int a[]={
1,2,3,4,5,6,7
};
MGraph G(a,7,8);
G.Clear(); //清理访问痕迹
G.DFSTraverse(0);
printf("\n");
G.Clear();
G.BFSTraverse(0);
Prim(G);
return 0;
}