最小生成树的Prim算法的延时实现和即时实现
2015-12-16 13:20
513 查看
Prim算法,每次总是将下一条连接树中的顶点与不在树中的顶点且权重最小的边加入树中。
Prim算法能够得到任意加权连通图的最小生成树。
数据结构:
顶点:使用一个布尔数组marked来表示顶点是否在最小生成树中
边:一条队列mst来保存最小生成树的边
横切边:用优先队列pq<Edge>来根据权重比较所有的边
重点:每当我们向最小生成树中添加了一条边之后,也向树中添加了一个顶点。要维护一个包含所有横切边的集合,就要将连接这个顶点和其他所有不在树中的顶点的边加入队列(用marked来识别这样的边)。但还有一点:连接新加入树中的顶点与其他已经在树中顶点的所有边都失效了。
Prim算法的即时实现可以将这样的边从优先队列中删掉
Prim算法的延时实现将这些边先留在优先队列中,等到要删除他们的时候再检查边的有效性
-LazyPrimMST.h 最小生成树的Prim算法的延时实现
-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;
}
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;
}
相关文章推荐
- hackbar使用简介!
- json与字符串互转
- Win7+VS2010环境下CEGUI 0.8.4编译过程详解
- JAVA 命名规则
- 【Android基础学习】动态设置 listView的高度,解决scrollView中嵌套listview时显示不全的问题
- 【codevs 1557】热浪的不同姿势
- JSON解析
- android GridLayout布局
- 杭电acm1086
- 使用freeMark生成word
- iOS 上基于js的monkey的测试
- ActionScript 3.0 按钮控制音乐播放、暂停、停止、循环
- 【单元测试】如何编写spring dao的单元测试类、基于注解
- mysql类似于oracle的decode的一种用法
- mysql binlog 分析
- 【WIN08R2 Active Directory】之一 部署企业中第一台Windows Server 2008 R2域控制器
- iOS基础框架的搭建/国际化操作
- 黑马程序员---Java基础篇之流程控制语句及控制跳转语句
- 利用spring的拦截器自定义缓存的实现
- Android UiAutomator编译与运行测试代码