2021-1 最小生成树 Prim算法的延时版本 c++

基本原理

关于横切边和切分定理,点这里 最小生成树理论准备
在这里插入图片描述
树中的边是黑色加粗,红色边为横切边,加粗红色为最短横切边,也是将要加入最小生成树的边。

解决三个问题

  • 最短横切边怎么找?

    用一条优先队列MinPQ来根据权重比较所有边

  • 如何保存切分?

    通过索引的布尔数组marked,标记已经加入树的节点(白色集合),自己的补集为灰色集合,两者构成一个切分。

  • 如何保存树?

    • 法一,通过一个队列mst保存最小生成树所有边
    • 法二,用一个父亲数组记录边,例如,edgeTo[v]记录着将v连入树中的Edge对象。

过程

  • 红色数字列举了横切边的信息【存放在队列中】,按权重排序。

  • 选取最小边保存,并出队(delMin)。新节点加入生成树,同时也有新的横切边入队(insert),重新调整得到最小值。

  • 值得注意的是随着一些新边的加入,队列中的某些边会失效(两个节点都在MST中,他们之间的边自然无效)。

注意:这里的时间复杂度关键看优先队列的提取最小值和插入的效率如何。记边数为E,因为队列里只存边。插入成本最坏 logE,提取最小值为2logE。而最多插入E条边,删除E次最小边,故而整个Prim算法时间最坏和ElogE成正比

在这里插入图片描述

MST基本API

在这里插入图片描述

Prim算法的延时(懒惰)版本

优先队列保存所有的横切边,但会包含失效边。用一条队列来保存最小生成树的边,用一个顶点索引来标记生成树的顶点。

//LazyPrimMST.h
#pragma once
#include<queue>
#include"EdgeWeightGraph.h"

typedef  priority_queue<Edge, vector<Edge>, greater<Edge> > MinPQ;


class LazyPrimMST
{
public:
	LazyPrimMST(EdgeWeightGraph& G);

	queue<Edge>* edges() { return m_mst; }
	double weight();

private:
	queue<Edge>* m_mst = nullptr;
	vector<bool>* m_marked = nullptr;
	MinPQ* m_pq=nullptr;

	void visit(EdgeWeightGraph& G, int v);//假定G联通
};

void testForLazyPrim();
#include "LazyPrimMST.h"

LazyPrimMST::LazyPrimMST(EdgeWeightGraph& G)
{
	m_marked = new vector<bool>(G.V(), false);
	m_mst = new queue<Edge>();
	m_pq = new MinPQ();

	visit(G, 0);//假定G是联通的
	while (!m_pq->empty())
	{
		Edge e = m_pq->top(); m_pq->pop();//取出最小边
		int v = e.either();
		int w = e.other(v);

		if (m_marked->at(v) && m_marked->at(w)) continue;//跳过失效边
		m_mst->push(e);//将边加入到树
		
		if (!m_marked->at(v)) visit(G, v);//将顶点加入到树v或w
		if (!m_marked->at(w)) visit(G, w);
	}
}

double LazyPrimMST::weight()
{
	return 0.0;
}

void LazyPrimMST::visit(EdgeWeightGraph& G, int v)
{//标记v,同时将所有 连接v和未被标记的顶点 的边加入m_pq
	m_marked->at(v) = true;
	for (Edge e : *G.adj(v)) {
		if (!m_marked->at(e.other(v))) m_pq->push(e);
	}
}

void testForLazyPrim()
{
	EdgeWeightGraph G("tinyEWG.txt");
	LazyPrimMST mst(G);
	queue<Edge>* edges = mst.edges();
	while (!edges->empty())
	{
		Edge e = edges->front(); edges->pop();
		out(e.toString()),hh;
	}
	hh;
}

头文件点这里 EdgeWeightGraph.h
运行

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值