Prim算法

13 篇文章 0 订阅
9 篇文章 0 订阅

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值