/*
Name: Prime算法求最小生成树 (最小堆优化)
Copyright:
Author: 巧若拙
Date: 28-02-17 08:43
Description: 实现了 Prime算法求最小生成树 (邻接矩阵)的最小堆优化算法。
*/
#include<iostream>
using namespace std;
const int MAX=2000; //最大顶点数量
const int INFINITY=999999; //无穷大
int map[MAX][MAX] = {0};//邻接矩阵存储图信息
class Vertex //图的结点类
{
public:
//void PrintVertex() {printf("(%d, %d) = %d", from, pos, dis);}
void SetVertex(int p, int d, int f) {pos = p; dis = d; from = f;}
void SetDis(int d) {dis = d;}
void SetFrom(int f) {from = f;}
int GetPos() {return pos;}
int GetDis() {return dis;}
int GetFrom() {return from;}
friend bool operator >(const Vertex &op1, const Vertex &op2) {return op1.dis > op2.dis;}
friend bool operator <(const Vertex &op1, const Vertex &op2) {return op1.dis < op2.dis;}
Vertex operator =(const Vertex &op) {pos = op.pos; dis = op.dis; from = op.from; return *this;}
private:
int pos;//存储顶点序号
int dis; //存储顶点到最小生成树的距离
int from; //入树介绍人
};
template <typename type> class MinHeap //一个简化的最小堆类
{
public:
MinHeap(int maxSize); //创建一个容量为maxSize的空堆
bool IsEmpty() const {return size == 0;}
bool IsFull() const {return size == capacity;}
type GetMin() const {return heap[0];} //返回堆顶的最小元素
bool Insert(const type &x); //将x插入到最小堆
bool DeleteMin(); //删除堆顶的最小元素
bool Change(const type &x, int i); //修改下标为i处元素的值,并调整堆
int Length() const {return size;} //返回堆的大小
type GetNode(int i) const {return heap[i];}
private:
type *heap; //存放堆的元素的数组
int capacity; //堆的容量
int size; //堆的长度,即当前元素个数
void FilterDown(int i); //从下标i到m自顶向下进行调整成为最小堆
void FilterUp(int i); //从下标i到0自底向上进行调整成为最小堆
};
template <typename type> MinHeap<type>::MinHeap(int maxSize)
{
capacity = maxSize;
heap = new type[capacity];
size = 0;
}
template <typename type> void MinHeap<type>::FilterDown(int i) //从下标i到堆的尾部自顶向下进行调整成为最小堆
{
type t = heap[i]; //保存heap[i]的值以备放到适合的位置
int child = i * 2 + 1; //指向左孩子
while (child < size) //有左孩子
{
if (child+1 < size && heap[child+1] < heap[child]) //有右孩子,且右孩子更小些,定位其右孩子
child += 1;
if (heap[child] < t)//用最小值覆盖其父亲结点的值,即将空位下滤到新的位置
{
heap[i] = heap[child];
i = child;
child = i * 2 + 1;
}
else
break;
}
heap[i] = t;
}
template <typename type> void MinHeap<type>::FilterUp(int i) //从下标i到0自底向上进行调整成为最小堆
{
type t = heap[i];
while (i > 0 && heap[i/2] > t) //若比父亲结点小,则用父亲结点的值覆盖该结点,即将空位上滤到新的位置
{
heap[i] = heap[i/2];
i /= 2;
}
heap[i] = t;
}
template <typename type> bool MinHeap<type>::Insert(const type &x) //将x插入到最小堆
{
if (IsFull())
{
cerr << "heap is full" << endl;
return false;
}
//从尾部插入并向上调整成最小堆,然后长度增1
heap[size++] = x;
FilterUp(size-1);
return true;
}
template <typename type> bool MinHeap<type>::Change(const type &x, int i) //修改下标为i处元素的值,并调整堆
{
if (i < 0 || i >= size)
{
cerr << "wrong pos" << endl;
return false;
}
if (heap[i] < x) //键值变大,向下调整
{
heap[i] = x;
FilterDown(i);
}
else if (heap[i] > x) //键值变小,向上调整
{
heap[i] = x;
FilterUp(i);
}
return true;
}
template <typename type> bool MinHeap<type>::DeleteMin() //删除堆顶的最小元素
{
if (IsEmpty())
{
cerr << "heap is empty" << endl;
return false;
}
heap[0] = heap[--size];//用尾部元素覆盖顶部元素,然后长度减1
FilterDown(0); //顶部元素向下调整成最小堆
return true;
}
void CreatGraph(int m, int n);//创建邻接矩阵图
void PrintGraph(int n);//输出图
void Prime_MinHeap(int n, int v0);//Prime算法求最小生成树(优先队列版本)
int main()
{
int i, j, m, n, v0 = 0;
printf("请输入顶点数量:");
scanf("%d", &n);
printf("\n请输入边数量:");
scanf("%d", &m);
CreatGraph(m, n);//创建邻接矩阵图
PrintGraph(n);//输出图
Prime_MinHeap(n, v0);//Prime算法求最小生成树(优先队列版本)
system("pause");
return 0;
}
void CreatGraph(int m, int n)//创建邻接矩阵图
{
int i, j, a, b, c;
for (i=0; i<n; i++) //初始化顶点数据
{
for (j=0; j<n; j++)
{
map[i][j] = (i == j) ? 0 : INFINITY;
}
}
printf("\n请按照a b c格式输入边信息:\n");
for (i=0; i<m; i++)
{
scanf("%d%d%d", &a,&b,&c);
map[a][b] = map[b][a] = c;
}
}
void PrintGraph(int n)//输出图
{
int i, j;
for (i=0; i<n; i++)
{
printf("G[%d] = %d: ", i, i);
for (j=0; j<n; j++)
{
if (map[i][j] != 0 && map[i][j] != INFINITY)
printf("<%d, %d> = %d", i, j, map[i][j]);
}
printf("\n");
}
printf("\n");
}
void Prime_MinHeap(int n, int v0)//Prime算法求最小生成树(优先队列版本)
{
Vertex vex;
MinHeap<Vertex> h(n);
int pos, dis, from;
for (int i=0; i<n; i++) //初始化工作,创建一个最小堆
{
vex.SetVertex(i, map[v0][i], v0);
h.Insert(vex);
}
h.DeleteMin(); //删除顶点v0
int minDis = 0;
for (int i=1; i<n; i++) //每趟确定一个新顶点,共n-1趟
{
//获取最小元素信息
vex = h.GetMin();
pos = vex.GetPos();
dis = vex.GetDis();
from = vex.GetFrom();
minDis += dis;
printf("<%d, %d> = %d ", from, pos, dis);
h.DeleteMin(); //删除最小元素
for (int j=0; j<h.Length(); j++)//更新顶点pos的邻接点的dis值,同时更新最小堆
{
vex = h.GetNode(j);
if (vex.GetDis() > map[pos][vex.GetPos()])
{
vex.SetFrom(pos);
vex.SetDis(map[pos][vex.GetPos()]);
h.Change(vex, j);
}
}
}
printf("最小生成树总长度(权值)为 %d\n", minDis);
}
Prime算法求最小生成树 (最小堆优化)
最新推荐文章于 2024-08-23 16:51:26 发布