堆是一颗完全二叉树,树中每个结点的值都不小于(或不大于)其左右孩子的值。其中,如果父亲结点的值大于或等于孩子结点的值,那么称这样的堆为大顶堆。如果父亲结点的值小于或等于孩子结点的值,那么称这样的堆为小顶堆。
堆的常用操作代码实现:
#include
#include
using namespace std;
const int maxn=100;
int heap[maxn],n=10;
//对heap数组在[low,high]范围进行向下调整
//其中low为欲调整结点的数组下标,high一般为堆最后一个元素的数组下标
void downAdjust(int low,int high){
int i=low,j=i*2; //i为欲调节结点,j为其左孩子
while(j<=high){ //存在孩子结点
//如果右孩子存在,且右孩子的值大于左孩子
if(j+1<=high&&heap[j+1]>heap[j])
j=j+1; //让j存储右孩子下标
//如果孩子中最大的权值比欲调整结点i大
if(heap[j]>heap[i]){
swap(heap[j],heap[i]); //交换最大权值的孩子与欲调整结点i
i=j; //保持i为欲调整结点,j为i的左孩子
j=i*2;
}
else{
break; //孩子的权值均比欲调整结点i小,调整结束
}
}
}
//对heap数组在[low,high]范围进行向上调整
//其中low为一般设置为1,high表示欲调整结点的数组下标
void upAdjust(int low,int high){
int i=high,j=i/2; //i为欲调节结点,j为其父亲
while(j>=high){ //父亲在[low,high]范围内
//如果孩子中最大的权值比欲调整结点i小
if(heap[j]=1;i--)
downAdjust(i,n);
}
//删除堆顶元素
void deleteTop(){
heap[1]=heap[n--]; //用最后一个元素覆盖堆顶元素,并让元素个数减1
downAdjust(1,n);
}
//添加元素x
void insert(int x){
heap[++n]=x; //让元素个数加1,然后将数组末位赋值为x
upAdjust(1,n); //向上调整新加入的结点n
}
//堆排序
void heapSort(){
createHeap(); //建立堆
for(int i=n;i>1;i--){ //倒着枚举,直到堆中只有一个元素
swap(heap[i],heap[1]); //交换heap[i]与堆顶
downAdjust(1,i-1); //调整堆顶
}
}
int main()
{
}
但在实际使用过程中往往通过c++STL库中的priority_queue来使用堆。
priority_queue又称优先队列,其底层是用堆来进行实现的。在优先队列中,队首元素一定是当前队列中优先级最高的那一个。
1.priority_queue的定义
要使用优先队列,应先添加头文件#include
其定义的写法和其他STL容器相同,typename可以是任意基本数据类型或容器:
priority_queue name;
2.priority_queue容器内元素的访问
和队列不一样的是,优先队列没有front()函数与back()函数,而只能通过top()函数来访问队首元素(也可以称为堆顶元素),也就是优先级最高的元素。
priority_queue q;
q.top();
3.priority_queue内元素优先级的设置
如何定义优先队列内元素的优先级是运用好优先队列的关键
(1)基本数据类型的优先级设置
优先队列对他们的优先级设置一般是数字大的优先级越高,因此队首元素就是优先队列内元素最大的那个(如果char型,则是字典序最大的)。对基本数据类型来说,下面两种优先队列的定义是等价的:
priority_queue q;
priority_queue,less>q;
第二个参数(vector
)填写的是来自承接底层数据结构堆(heap)的容器,该参数类型必须与第一个参数类型相同,第三个参数less
则是对第一个参数的比较类,less
表示数字大的优先级越大,而greater
表示数字小的优先级越大。
(2)结构体的优先级设置
struct fruit{
string name;
int price;
friend bool operator<(fruit f1,fruit f2){
return f1.price
上面的结构体中对小于号进行重载,重载大于号会编译错误,因为从数学角度来说只需重载小于号,即f1>f2等价于判断f2
注意:
使用top()函数前,建议用empty()判断优先队列是否为空,否则可能因为队空而出现错误。