现在的位置: 首页 > 综合 > 正文

有向加权图的最短路径算法-Prim

2018年02月20日 ⁄ 综合 ⁄ 共 4949字 ⁄ 字号 评论关闭

1 无向加权图的数据格式如下

4 5 0.35
4 7 0.37
5 7 0.28
0 7 0.16
1 5 0.32
0 4 0.38
2 3 0.17
1 7 0.19
0 2 0.26
1 2 0.36
1 3 0.29
2 7 0.34
6 2 0.40
3 6 0.52
6 0 0.58
6 4 0.93

2 实现的C++代码如下,包括无向加权边,无向图和Prim算法

Graph.h头文件内容
/*
 * Graph.h
 *
 *  Created on: 2014年5月17日
 *      Author: zhongchao
 */

#ifndef _GRAPH_
#define _GRAPH_


#include <fstream>
#include <iostream>
#include <ext/hash_map>
#include <hash_set>
#include <map>
#include<limits>
#include <stdio.h>
#include <string.h>

using namespace std;
using namespace __gnu_cxx;
//-------------------------最小生成树算法------------------
class WeightEdge
{
private:
		int _a; //起点
		int _b;       //终点
		double _weight; //权重
public:
		WeightEdge();
		WeightEdge(int a, int b, double c);
		~WeightEdge();
		int one();
		int other(int a);
		double weight();
};

class WeightGraph
{
private:
		hash_map<int, vector<WeightEdge*> > adj; //邻接表
		hash_set<int> nodes;
		int _eNum; //边的个数
		int _vNum; //节点个数

public:
		WeightGraph(string path);
		~WeightGraph();
		void addEdge(int f,  int t, double w);
		vector<WeightEdge*> getAdj(int n);
		int e();
		int v();
		vector<WeightEdge*> edges(int node);
		hash_set<int> getNodes();
};

class Prim
{
private:
		bool* mark;
		double* distTo;
		WeightEdge** edgeTo;
		map<double, int> pq;
		hash_set<int> pqMark;
		WeightGraph* _graph;
		int startNode;
public:
		Prim(WeightGraph* graph, int n);
		void visit(WeightGraph* graph, int n);
		vector<WeightEdge*> edges();
		double weight();
		void printEdges(vector<WeightEdge*> & edges);
};

//----------------------------------------------------------------------
#endif /* _GRAPH_*/

Graph.h对应的源文件

/*
 * Graph.cpp
 *
 *  Created on: 2014年5月17日
 *      Author: zhongchao
 */
#include "Graph.h"
/*
 * 无向加权图算法
 */
//-------------------------无向加权边------------------------------
WeightEdge::WeightEdge()
{
}
WeightEdge::WeightEdge(int a, int b, double c)
{
		this->_a = a;
		this->_b = b;
		this->_weight = c;
}
WeightEdge::~WeightEdge()
{}
int WeightEdge::one()
{
		return _a;
}
int WeightEdge::other(int a)
{
		if(_a == a)
				return _b;
		else
				return _a;
}
double WeightEdge::weight()
{
		return _weight;
}
//----------------------------------------------------------------------
//----------------------无向加权图-----------------------------
hash_set<int> WeightGraph::getNodes()
{
		return nodes;
}
void WeightGraph::addEdge(int f,  int t,  double w)
{
		WeightEdge* weightEdge = new WeightEdge(f, t, w);
		if(adj.find(f) != adj.end())
		{
				adj.find(f)->second.push_back(weightEdge);
		}
		else
		{
				vector<WeightEdge*> edges;
				edges.push_back(weightEdge);
				adj.insert(pair<int, vector<WeightEdge*> >(f, edges));
		}
}
WeightGraph::WeightGraph(string path)
{
		this->_eNum = 0;
		this->_vNum = 0;
		ifstream reader(path.c_str(),  ios_base::in);
		if(reader.is_open())
		{
				while(!reader.eof())
				{
						int f, t;
						double w;
						reader>>f>>t>>w;
						if(reader.fail())
								break;
						//cout<<f<<" "<<t<<" "<<w<<endl;
						nodes.insert(f);
						nodes.insert(t);
						addEdge(f, t, w);
						addEdge(t, f, w);
						_eNum++;   //边的条数
				}
		}
}

int WeightGraph::e()
{
		return _eNum;
}

int WeightGraph::v()
{
		return nodes.size();
}
vector<WeightEdge*> WeightGraph::getAdj(int n)
{
		return adj.find(n)->second;
}
WeightGraph::~WeightGraph()
{
			for(hash_map<int, vector<WeightEdge*> >::iterator it = adj.begin(); it != adj.end(); it++)
			{
					for(vector<WeightEdge*>::iterator it1 = it->second.begin(); it1 != it->second.end(); it1++)
					{
							delete *it1;
					}
			}
}
//---------------------------------------------------------------------
//-------------------------Prim算法---------------身不由己-------------
Prim::Prim(WeightGraph* graph, int n)
{
		startNode = n;
		_graph = graph;
		mark = new bool[graph->v()];
		distTo = new double[graph->v()];
		edgeTo = new WeightEdge*[graph->v()];
		int tt= graph->v();
		for(int i = 0; i < graph->v(); i++)
		{
				mark[i] = false;
				distTo[i] = numeric_limits<double>::max();
		}
		mark[n] = true;
		distTo[n] = 0.0;
		pq.insert(pair<double, int>(0.0, n));
		pqMark.insert(n);

		while(pq.size() > 0)
		{
				int v = pq.begin()->second;
				pq.erase(pq.begin());
				visit(graph, v);
		}

}

void Prim::visit(WeightGraph* graph, int n)
{
		mark[n] = true;
		vector<WeightEdge*> edges = graph->getAdj(n);
		for(vector<WeightEdge*>::iterator it = edges.begin(); it != edges.end(); it++)
		{
				int o = (*it)->other(n);
				double w = (*it)->weight();
				if(mark[o] == true) continue;
				if(w < distTo[o])
				{
						edgeTo[o] = *it;
						distTo[o] = w;
						if(pqMark.find(o) == pqMark.end())
						{
								pq.insert(pair<double, int>(w, o));
								pqMark.insert(o);
						}
						else
						{
								for(map<double, int>::iterator it = pq.begin(); it != pq.end(); it++)
								{
										if((it)->second == o)
										{
												pq.erase(it);
												pq.insert(pair<double, int>(w, o));
												break;
										}
								}
						}
				}
		}
}
vector<WeightEdge*> Prim::edges()
{
		vector<WeightEdge*> es;
		for(int i = 0; i < _graph->v(); i++)
		{
				if(i == startNode) continue;
				es.push_back(edgeTo[i]);
		}
		return es;
}
double Prim::weight()
{
		double w = 0.0;
		for(int i = 0; i < _graph->v(); i++)
		{
				if(i == startNode) continue;
				w += distTo[i];
		}
		return w;
}
void Prim::printEdges(vector<WeightEdge*> & edges)
{
		cout<<"The MST as follows:"<<endl;
		for(vector<WeightEdge*>::iterator it = edges.begin(); it != edges.end(); it++)
		{
				cout<<(*it)->one()<<"    "<<(*it)->other((*it)->one())<<"    "<<(*it)->weight()<<endl;
		}
		cout<<"Total weight is: "<<weight()<<endl;
}
//--------------------------------------------------------------------

测试程序

/*
 * Run.cpp
 *
 *  Created on: 2014年5月25日
 *      Author: zhongchao
 */

#include "Graph.h"
int main(int argc, char** argv)
{
	//最小生成树算法
	string path("/home/zhongchao/worksapce/cpp/ComputeAlgorithms/data/tinyEWG.txt");
	WeightGraph* weightGraph = new WeightGraph(path);
	int n = 2;
	Prim* prim = new Prim(weightGraph, n);
	vector<WeightEdge*> es = prim->edges();
	prim->printEdges(es);
	return 1;
}

以节点2为起点的最小生成树如下

The MST as follows:
2    0    0.26
7    1    0.19
2    3    0.17
5    4    0.35
7    5    0.28
2    6    0.4
0    7    0.16
Total weight is: 1.81

抱歉!评论已关闭.