Prim算法实现最小生成树MST

1 篇文章 0 订阅
1 篇文章 0 订阅

//实现文件

#include <queue>
#include <vector>
#include <list>
#include <cassert>
#include <iostream>
using namespace std;
//用STL中的优先队列实现
namespace prim_priority
{
	const static int MAX_VERTEX_NUM = 100;
	const static int INVALID_VNAME = -1;
	const static double INVALID_LENGTH = 10000.0;

	typedef struct _Node 
	{
		int vname;
		int vname_pre;
		double len;
		_Node(void)
		{
			vname = INVALID_VNAME;
			vname_pre = INVALID_VNAME;
			len = INVALID_LENGTH;
		}
		_Node(int v, int v_pre, double l):vname(v),vname_pre(v_pre),len(l){}
	}Node, *pNode;

	class Cmp
	{
	public:
		bool operator()(const Node &l, const Node &r)
		{
			return l.len > r.len;
		}
	};

	vector< list<Node> > vGraph;	//graph
	vector<Node> vPath;
	double iMinPathLen;	//min tree path length
	int iVertexNum;

	double Prim(void)
	{
		iVertexNum = vGraph.size()-1;
		assert(iVertexNum<MAX_VERTEX_NUM);
		vPath.clear();
		iMinPathLen = 0;

		priority_queue< Node, vector<Node>, Cmp > pq;
		bool used[MAX_VERTEX_NUM];
		memset(used, false, sizeof(used));

		int iUsedNum(0), iCurVertex(1);
		Node tmp;
		iUsedNum = 1;
		used[iCurVertex] = true;
		while ( iUsedNum<iVertexNum )
		{
			for ( list<Node>::iterator it=vGraph[iCurVertex].begin(); 
				it!=vGraph[iCurVertex].end(); ++it)
			{
				if ( !used[it->vname])
					pq.push(*it);
			}

			while (!pq.empty() && !(used[(Node(pq.top())).vname_pre] && !used[(Node(pq.top())).vname]) )
				pq.pop();
			if (pq.empty())
				break;

			tmp = pq.top();
			pq.pop();
			vPath.push_back(tmp);

			iMinPathLen += tmp.len;
			used[tmp.vname] = true;
			iCurVertex = tmp.vname;
			++iUsedNum;
		}

		return iMinPathLen;
	}

	void PrintMinPath(void)
	{
		cout << "minpath: " << iMinPathLen << endl;
	}

	void PrintPath(void)
	{
		cout << "path selection process" << endl;
		for ( unsigned int i=0; i<vPath.size(); ++i )
			cout << vPath[i].vname_pre << "-->" << vPath[i].vname 
			<< "("<< vPath[i].len <<")" << endl;
	}

	void PrintResult(void)
	{
		PrintPath();
		PrintMinPath();
	}

	void PrintGraph(void)
	{
		cout << "graph:" << endl;
		int i(1);
		vector<list<Node> >::iterator it=vGraph.begin();
		for ( ++it; it!=vGraph.end(); ++it)
		{
			cout << i << ": ";
			for ( list<Node>::iterator l=(*it).begin();l!=(*it).end(); ++l)
				cout << l->vname << "("<< l->len << ") ";
			cout << endl;
			++i;
		}
	}
};

//普通实现方式
namespace prim_simple
{
	const static int MAX_VERTEX_NUM = 100;
	const static int INVALID_VERTEX = -1;
	const static double INVALID_WEIGHT = 100000.0;

	typedef struct _TreeEdge
	{
		int v1;
		int v2;
		double w;
		_TreeEdge(int _v1, int _v2, double _w):v1(_v1), v2(_v2), w(_w){}
		_TreeEdge(void)
		{
			v1 = v2 = INVALID_VERTEX;
			w = INVALID_WEIGHT;
		}
	}TreeEdge;

	typedef struct _ChosenEdge
	{
		int v2;
		double w;
		_ChosenEdge(void)
		{
			v2 = INVALID_VERTEX;
			w = INVALID_WEIGHT;
		}
	}ChosenEdge;

	double vGraph[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
	TreeEdge vMSTree[MAX_VERTEX_NUM];
	ChosenEdge vCEdge[MAX_VERTEX_NUM];
	bool vbInTree[MAX_VERTEX_NUM];
	int iVertexNum;
	double dMinWPath;

	double Prim(void)
	{
		//init
		memset( vbInTree, false, sizeof(vbInTree));
		dMinWPath = 0.0;
		assert(iVertexNum>0 && iVertexNum<MAX_VERTEX_NUM);

		int i(1);
		for ( ;i<iVertexNum; ++i )
		{
			vCEdge[i].v2 = 1;
			vCEdge[i].w = vGraph[i][1];
		}
		vMSTree[1].v1 = 1;
		vMSTree[1].v2 = 0;
		vMSTree[1].w = -1.0;
		vbInTree[1] = true;

		//calc
		int j(0), k(0);
		for ( i=2; i<=iVertexNum; ++i)
		{
			for ( k=1; k<=iVertexNum && vbInTree[k]; ++k);
			if ( k>iVertexNum )
				break;

			for ( j=k; j<=iVertexNum; ++j)
			{
				if ( !vbInTree[j] && vCEdge[k].w>vCEdge[j].w )
					k = j;
			}

			//add
			vMSTree[i].v1 = k;
			vMSTree[i].v2 = vCEdge[k].v2;
			vMSTree[i].w  = vCEdge[k].w;
			dMinWPath += vCEdge[k].w;
			vbInTree[k] = true;

			//adjust
			for ( j=1; j<=iVertexNum; ++j )
			{
				if ( !vbInTree[j] && vCEdge[j].w>vGraph[j][k])
				{
					vCEdge[j].w = vGraph[j][k];
					vCEdge[j].v2 = k;
				}
			}
		}

		return dMinWPath;
	}

	void PrintMinPath(void)
	{
		cout << "minpath: " << dMinWPath << endl;
	}

	void PrintPath(void)
	{
		cout << "path selection process" << endl;
		for ( int i=1; i<=iVertexNum; ++i )
		{
			cout << vMSTree[i].v2 << "-->" << vMSTree[i].v1
			<< "("<< vMSTree[i].w <<")" << endl;
		}
	}

	void PrintResult(void)
	{
		PrintPath();
		PrintMinPath();
	}

	void PrintGraph(void)
	{
		cout << "graph:" << endl;
		for (int i=1; i<=iVertexNum; ++i)
		{
			cout << i <<": ";
			for ( int j=1; j<=iVertexNum; ++j)
			{
				if ( vGraph[j][i]<INVALID_WEIGHT )
				{
					cout<< j <<"(" << vGraph[j][i] << ") ";
				}
			}
			cout << endl;
		}
	}

	void PrintAll(void)
	{
		PrintGraph();
		PrintResult();
	}


};


//测试文件

#include <iostream>
#include <cstdlib>
#include "Prim.h"
using namespace std;

int main()
{
	//测试优先队列实现的Prim算法
	{
		using namespace prim_priority;
		cout << "prim_priority" << endl;

		list<Node> l;
		//v0
		l.push_back(Node(-1, 0, -1));
		vGraph.push_back(l);
		//v1
		l.clear();
		l.push_back(Node(2, 1, 2));
		l.push_back(Node(3,1, 4));
		l.push_back(Node(4,1, 1));
		vGraph.push_back(l);
		//v2
		l.clear();
		l.push_back(Node(1,2, 2));
		l.push_back(Node(4,2, 3));
		l.push_back(Node(5,2, 10));
		vGraph.push_back(l);
		//v3
		l.clear();
		l.push_back(Node(1,3, 4));
		l.push_back(Node(4, 3,2));
		l.push_back(Node(6,3, 5));
		vGraph.push_back(l);
		//v4
		l.clear();
		l.push_back(Node(1, 4,1));
		l.push_back(Node(2, 4,3));
		l.push_back(Node(3, 4,2));
		l.push_back(Node(5,4, 7));
		l.push_back(Node(6, 4,8));
		l.push_back(Node(7, 4,4));
		vGraph.push_back(l);
		//v5
		l.clear();
		l.push_back(Node(2, 5,10));
		l.push_back(Node(4, 5,7));
		l.push_back(Node(7, 5,6));
		vGraph.push_back(l);
		//v6
		l.clear();
		l.push_back(Node(3, 6,5));
		l.push_back(Node(4, 6,8));
		l.push_back(Node(7, 6,1));
		vGraph.push_back(l);
		//v7
		l.clear();
		l.push_back(Node(4, 7,4));
		l.push_back(Node(5, 7,6));
		l.push_back(Node(6, 7,1));
		vGraph.push_back(l);

		Prim();
		PrintGraph();
		PrintResult();
	}

	cout << endl;

	//测试普通方式实现的Prim算法
	{
		using namespace prim_simple;
		cout << "prim_simple" << endl;

		iVertexNum = 7;
		for ( int i=0; i<MAX_VERTEX_NUM*MAX_VERTEX_NUM; ++i)
			vGraph[i/MAX_VERTEX_NUM][i%MAX_VERTEX_NUM] = INVALID_WEIGHT;

		//v1
		vGraph[2][1] = 2;
		vGraph[3][1] = 4;
		vGraph[4][1] = 1;
		//v2
		vGraph[1][2] = 2;
		vGraph[4][2] = 3;
		vGraph[5][2] = 10;
		//v3
		vGraph[1][3] = 4;
		vGraph[4][3] = 2;
		vGraph[6][3] = 5;
		//v4
		vGraph[1][4] = 1;
		vGraph[2][4] = 3;
		vGraph[3][4] = 2;
		vGraph[5][4] = 7;
		vGraph[6][4] = 8;
		vGraph[7][4] = 4;
		//v5
		vGraph[2][5] = 10;
		vGraph[4][5] = 7;
		vGraph[7][5] = 6;
		//v6
		vGraph[3][6] = 5;
		vGraph[4][6] = 8;
		vGraph[7][6] = 1;
		//v7
		vGraph[4][7] = 4;
		vGraph[5][7] = 6;
		vGraph[6][7] = 1;

		Prim();
		PrintAll();
	}

	system("pause");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值