您的位置:首页 > 其它

最小生成树的Prim算法的延时实现和即时实现

2015-12-16 13:20 513 查看
Prim算法,每次总是将下一条连接树中的顶点与不在树中的顶点且权重最小的边加入树中。

Prim算法能够得到任意加权连通图的最小生成树。

数据结构:

顶点:使用一个布尔数组marked来表示顶点是否在最小生成树中

边:一条队列mst来保存最小生成树的边

横切边:用优先队列pq<Edge>来根据权重比较所有的边

重点:每当我们向最小生成树中添加了一条边之后,也向树中添加了一个顶点。要维护一个包含所有横切边的集合,就要将连接这个顶点和其他所有不在树中的顶点的边加入队列(用marked来识别这样的边)。但还有一点:连接新加入树中的顶点与其他已经在树中顶点的所有边都失效了。

Prim算法的即时实现可以将这样的边从优先队列中删掉

Prim算法的延时实现将这些边先留在优先队列中,等到要删除他们的时候再检查边的有效性

-LazyPrimMST.h 最小生成树的Prim算法的延时实现

#ifndef __LAZY_PRIM_MST_H__
#define __LAZY_PRIM_MST_H__

#include <queue>
#include <functional>
#include "EdgeWeightedGraph.h"
#include "Edge.h"
/**
* Prim算法的延时删除实现
* 延时删除:新加入树中的顶点与其他已经在树中的顶点的边不立即删除,
*	将这些边先留在优先队列中,等到要删除他们的时候再检查边的有效性
*/
class LazyPrimMST {
private:
bool* marked;					// 最小生成树的顶点
std::queue<Edge> mst;			// 最小生成树的边
std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge> > pq;	// 横切边(包括失效的边)
double weight;

public:
LazyPrimMST(const EdgeWeightedGraph& G);
~LazyPrimMST() { delete[] marked; }

std::queue<Edge> getMst()const { return mst; }
double getWeight()const;

private:
void visit(const EdgeWeightedGraph& G, int v);
};

// constructor
LazyPrimMST::LazyPrimMST(const EdgeWeightedGraph& G) {
weight = 0.0;
marked = new bool[G.getV()];
for (int i = 0; i < G.getV(); ++i) {
marked[i] = false;
}

visit(G, 0);
for (;;) {
Edge e = pq.top();
pq.pop();
int v = e.either();
int w = e.other(v);
//跳过失效的边
if (marked[v] && marked[w]) continue;
mst.push(e);
weight += e.getWeight();
// 如果边数为顶点数-1则最小生成树完成了
if (mst.size() == G.getV() - 1) break;
if (!marked[v]) visit(G, v);
else if (!marked[w]) visit(G, w);
}
}

/**
* 标记顶点v并将所有连接v和未被标记的顶点的边加入pq
*/
void LazyPrimMST::visit(const EdgeWeightedGraph& G, int v)
{
marked[v] = true;
for (Edge e : G.getAdj(v)) {
if (!marked[e.other(v)]) {
pq.push(e);
}
}
}

// weight
double LazyPrimMST::getWeight()const {
return weight;
}

#endif



-PrimMST.h Prim算法的即时实现 

#ifndef __PRIM_MST_H__
#define __PRIM_MST_H__

#include "Edge.h"
#include "EdgeWeightedGraph.h"
#include <queue>
#include <map>

class PrimMST {
private:
typedef std::map<double, int>::const_iterator IntDoubleMapIter;
int vNum; // 边数
Edge *edgeTo; // 距离树最近的边
double *distTo; // distTo[w] = edgeTo[w].weight()
bool *marked; // 如果v在树中则为true
std::map<double, int> map; // key:横切边的权值,value:顶点

public:
PrimMST(const EdgeWeightedGraph& G);
~PrimMST() { delete[] edgeTo; delete[] distTo; delete[] marked; }

double getWeight()const;
std::list<Edge> edges()const;

private:
void visit(const EdgeWeightedGraph& G, int v);

};

// constructor
PrimMST::PrimMST(const EdgeWeightedGraph& G) {
vNum = G.getV();
edgeTo = new Edge[vNum];
distTo = new double[vNum];
for (int i = 0; i < vNum; ++i) distTo[i] = DBL_MAX;
marked = new bool[vNum];
for (int i = 0; i < vNum; ++i) marked[i] = false;

distTo[0] = 0;
map[0.0] = 0;
while (!map.empty()) {
// 每次都将权重最小的pop出来
// 类似优先队列的操作,不过优先队列没有key和value
// 可以用带索引的优先列队来替代
IntDoubleMapIter iter = map.begin();
int v = iter->second; // 权值最小的边的顶点
map.erase(iter);
visit(G, v);
}
}

// visit
void PrimMST::visit(const EdgeWeightedGraph& G, int v) {

marked[v] = true;
for (Edge e : G.getAdj(v)) {
int w = e.other(v);

if (marked[w]) continue; // w也在最小生成树中
if (e.getWeight() < distTo[w]) {
// 最小生成树到顶点w权重最小的边为e
edgeTo[w] = e;
// 连接w顶点的权重
distTo[w] = e.getWeight();
// 将权重-顶点添加进map
map[distTo[w]] = w;
}
}
}

// weight
double PrimMST::getWeight()const {
double weight = 0.0;
for (int i = 0; i < vNum; ++i) {
weight += distTo[i];
}
return weight;
}

// edges
std::list<Edge> PrimMST::edges()const {
std::list<Edge> lst;
for (int i = 0; i < vNum; ++i) {
lst.push_back(edgeTo[i]);
}
return lst;
}

#endif

-main.cpp 测试用例
#include "PrimMST.h"
#include "Edge.h"
#include "EdgeWeightedGraph.h"
#include <iostream>
using namespace std;

int main()
{
int vNum, eNum;
cin >> vNum >> eNum;
EdgeWeightedGraph G(vNum);

int v, w;
double weight;
for (int i = 0; i < eNum; ++i){
cin >> v >> w >> weight;
Edge e(v, w, weight);
G.addEdge(e);
}

PrimMST primMST(G);
for (Edge e : primMST.edges()) {
cout << e.either() << "-"
<< e.other(e.either()) << " "
<< e.getWeight() << endl;
}
cout << "total weight: " << primMST.getWeight();

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: