算法导论:基于最小优先队列实现prim算法的伪代码复现原始版及c++的STL(priority_queue)的简易实现版

本文详细介绍Prim最小生成树算法的两种实现方式:一种通过手写小顶堆实现优先队列,另一种借助C++ STL中的priority_queue。文章提供了完整的代码示例及解析,帮助读者深入理解算法原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

优先队列算法导论伪代码见上回:
算法导论:c/c++代码复现小顶堆实现优先队列

1. 算法导论prim算法伪代码复现

伪代码源于算法导论


build-min-heap(A):
    A.heapsize <- A.length
    for i in [A.length/2] downto 1
        Min-heapify(A,i)

Min-heapify(A,i):
    l<-2*i,r<-2i+1
    min<-i
    if l <= A.heapsize and A[l] < A[i]
        min <- l
    if r <= A.heapsize and A[r] < A[i]
        min<- r
    if min != i
        A[i]<-> A[min]
        min-hepify(A,min)

Get-Min(A):
    return A[1];

Extract-Min(A):
    min<-A[1];
    A[1]<-->A[A.heapsize];
    A.heapsize <- A.heapsize-1;
    min-heapity[A,1]
    return min;

Decrease-Key(A,i,k):
    A[i]<-k;
    while i>1 and A[i]<A[i/2] do
        A[i] <-> A[i/2]
        i<-[i/2]

insert(A,key):
    A.heapsize <- A.heapsize+1
    A[A.heapsize] <- inf
    Decrease-Key(A,A.heapsize,key)


MST-Prim(G,w,s):
	for each u in V do
		u.key <- +oo
		u.p <- NULL
	s.key <- 0
	Q <- V
	while !Q.empty() do
		u <- Extract-Min(Q)
		for each (u,v) in E do
			if v in Q and w(u,v) < v.key then
				v.p <- u
				Decrease-Key(Q,v,w(u,v))

在这里插入图片描述
c++代码复现(变量函数名等同算法导论伪代码基本保持一致):

#include<iostream>
#include<stdio.h>
#include<map>
#include<vector>
#include<set>
using namespace std;

struct Node {
	int num;//所在数组下标序号
	int p;//父节点下标序号
	int key;//到源点距离
};

class MyArray {
public:
	MyArray(int size, int len, Node arr[100]) {
		this->heapsize = size;
		this->length = len;
		for (int i = 0; i <= length; i++) {
			this->arr[i] = arr[i];
		}
	}
	MyArray(int size, int len) {
		this->heapsize = size;
		this->length = len;
	}

	int heapsize, length;
	Node arr[100];
};


vector<pair<int, int> > v[100];
set<int> st;
int vis[100] = { 0 };

void min_heapify(MyArray &a, int i) {
	int min = i;
	int l = i * 2, r = i * 2 + 1;

	if (l <= a.heapsize && a.arr[i].key > a.arr[l].key) {
		min = l;
	}
	if (r <= a.heapsize && a.arr[min].key > a.arr[r].key) { //易错点
		min = r;
	}
	if (min != i) {
		swap(a.arr[min], a.arr[i]);
		min_heapify(a, min);
	}
}
void bulid_min_heap(MyArray& a) {
	a.heapsize = a.length;
	for (int i = a.length / 2; i >= 1; i--) {
		min_heapify(a, i);
	}
}

int extract_min(MyArray &a) {
	int t = a.arr[1].num;
	swap(a.arr[1], a.arr[a.heapsize]);
	a.heapsize--;
	min_heapify(a, 1);
	return t;
}

void decrease(MyArray&a, int i, int key) {
	a.arr[i].key = key;
	while (i > 1 && a.arr[i / 2].key > a.arr[i].key) {
		swap(a.arr[i / 2], a.arr[i]);
		i /= 2;
	}
}

int find_index(MyArray&a,int num){
    int ori;
    for (int j = 1; j <= a.length; j++) {
        if (a.arr[j].num == num) {
            ori = j;
            break;
        }
    }
    return ori;
}
void mst_prim(MyArray& a, int s) {
	for (set<int>::iterator it = st.begin(); it != st.end(); it++) {
		a.arr[*it].key = 0xffff;
		a.arr[*it].p = -1;
		a.arr[*it].num = *it;
	}
	a.arr[s].key = 0;
	bulid_min_heap(a);

	int num = st.size();
	while (num--) {
		int u = extract_min(a);
		vis[u] = 1;
		for (int i = 0; i < v[u].size(); i++) {
			int ori = find_index(a,v[u][i].first);
			if(vis[v[u][i].first]){
                continue;
			}
			if (v[u][i].second < a.arr[ori].key) {
				a.arr[ori].p = u;
				decrease(a, ori, v[u][i].second);
			}
		}
	}

}
void insert(MyArray &a,int key){
    a.heapsize++;
    a.arr[a.heapsize].key = 0xffff;
    decrease(a,a.heapsize,key);
}
//author: GUET_diadestiny
int main() {
	int bian;
	cin >> bian;
	while (bian--) {
		int a, b, val;
		cin >> a >> b >> val;
		v[a].push_back(make_pair(b,val));
		v[b].push_back(make_pair(a,val));
		st.insert(a);
		st.insert(b);
	}
	MyArray a(st.size(), st.size());
	mst_prim(a, 1);
	cout<<a.heapsize<<endl;
	for (int i = 1; i <= a.length; i++) {
		cout<< a.arr[i].num<< " " << a.arr[i].p << " "<< a.arr[i].key << endl;
	}
	return 0;
}

2. 基于STL(priority_queue)的简易实现版

算法思想和书上基本一致,但是由于priority_queue优先队列结构的使用方法,采用的是边插入节点边调整处理的方法。
(算法导论中采用的是全部插入后再调整处理的方法)

实现代码:

#include<iostream>
#include<cstring>
#include<vector>
#include<queue>

using namespace std;
#define INf 0x3f3f3f
#define N 1050
int dis[N];//最小距离数组,保存的是父节点到该节点n的最小距离
int vis[N]={0};//标记数组
typedef pair<int,int> P;
vector<P> v[N];//邻接表
//邻接表
struct cmp
{
    bool operator()(P p1,P p2){
        return p1.second>p2.second;
    }
};
//自定义比较优先排序
priority_queue<pair<int,int>, vector<pair<int,int> >, cmp> que;//最小优先队列(c++STL容器中的优先队列)

void prime(int n)
{
	
	dis[0] = 0;
	que.push(make_pair(0,0));
	while(!que.empty())
	{
		P temp = que.top();
		que.pop();
		int ori = temp.first;
		if (vis[ori] == 1)
		{
			continue;
		}
		vis[ori] = 1;
		for (int i = 0; i < n; i++)
		{
			P x = v[ori][i];
			if (vis[x.first] != 1 && dis[x.second] > x.second)
			{
				dis[x.first] = x.second;
				que.push(make_pair(x.first, dis[x.first]));
			}
		}
	}
	
}
//author: GUET_diadestiny
int main()
{
    int n,distance;
	memset(dis, INf, sizeof(dis));//初始化距离数组
    cin >> n;

    //建立邻接表
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{   
			cin >> distance;
			v[i].push_back(make_pair(j, distance));
		}
	}
	prime(n);
    int res = 0;
	for (int i = 0; i < n; i++)
	{
		res = res + dis[i];
	}
	cout << "最小生成树权值: " << res << endl;
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值