优先队列算法导论伪代码见上回:
算法导论: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;
}