priority_queue与堆

1.priority_queue(优先级队列)

优先级队列的底层是堆,每次队首元素都是优先级最大的。

头文件

include<queue>
using namespace std;

常用操作

  • push()

push(x)令x入队,复杂度O(logN)

  • top()

获取队首元素,复杂度O(1)

  • pop()

令队首元素出队,复杂度O(logN)

  • empty()

检测优先队列是否为空,复杂度O(1)

  • size()

返回优先队列内元素个数,复杂度O(1)

优先级设置

(1)基本数据类型的优先级设置

priority_queue q == priority_queue<int,vector, less > q;

上面两种表述方式作用相同,其中vector表示承载优先级队列的容器, less表示数字大的优先级越大,进一步理解可以是less重栽了小于号运算(注意只能重载小于号运算!!).

//优先级队列优先级设置 
#include <iostream>
#include <queue>
using namespace std;

int main(){
	//---1---基本数据类型:设置优先级队列总是把最小的元素放在队首 
	priority_queue<int,vector<int>,greater<int> > q;//注意<int> >之间的空格 
	q.push(3);
	q.push(4);
	q.push(1);
	printf("%d\n",q.top());
	return 0;
}

(2)结构体的优先级设置

  • 方式一: 小于号重载在结构体内部
//结构体优先级设置 
#include <iostream>
#include <queue>
using namespace std;
struct fruit{
	string name;
	int price;
	friend bool operator < (fruit f1,fruit f2){
		return f1.price < f2.price;
	}
}f1,f2,f3; 

int main(){
	priority_queue<fruit> q;
	f1.name = "桃子";
	f1.price = 3;
	f2.name = "梨子";
	f2.price = 4;
	f3.name = "苹果";
	f3.price = 1;
	q.push(f1);
	q.push(f2);
	q.push(f3); 
	cout<<q.top().name<<" "<<q.top().price<<endl;
	return 0;
}
  • 方式二: 小于号重载在结构体外部
#include <iostream>
#include <queue>
using namespace std;
struct fruit{
	string name;
	int price;
	friend bool operator < (fruit f1,fruit f2){
		return f1.price < f2.price;
	}
}f1,f2,f3; 

struct cmp{
	bool operator () (fruit f1,fruit f2){
		return f1.price > f2.price;
	}
};

int main(){
	//重载优先级结构体进行排序 
	priority_queue<fruit> q;
	f1.name = "桃子";
	f1.price = 3;
	f2.name = "梨子";
	f2.price = 4;
	f3.name = "苹果";
	f3.price = 1;
	q.push(f1);
	q.push(f2);
	q.push(f3); 
	cout<<q.top().name<<" "<<q.top().price<<endl;
	//用cmp函数优先级排序 
	priority_queue<fruit,vector<fruit>,cmp> qq;
	f1.name = "桃子";
	f1.price = 3;
	f2.name = "梨子";
	f2.price = 4;
	f3.name = "苹果";
	f3.price = 1;
	qq.push(f1);
	qq.push(f2);
	qq.push(f3); 
	cout<<qq.top().name<<" "<<qq.top().price<<endl;
	return 0;
}

应用练习

复数集合(北邮)

哈夫曼树(北邮)

2.堆的定义

堆是一棵完全二叉树,树中每个结点的值都不小于(或不大于)其左右孩子结点的值。
大顶堆:父节点值>=孩子结点的值 此时父节点的值为子树最大
小顶堆:父节点值<=孩子结点的值 此时父节点的值为子树最小

堆是完全二叉树,一般用数组来存储

const int maxn=100;
//heap数组存储堆 n为实际数组元素个数
int heap[maxn],n=10;

基本操作

向下调整(O(logn))

//单个结点的向下调整  O(logn)
//对heap下标为low的结点进行调整 high为数组中最后一个元素下标
void downAdjust(int low,int high){
	int i=low,j=low*2;//i为欲调整的下标   j为左孩子
	while(j<high){//有左孩子
		//注意 先判断j+1<high
		if(j+1<high&&heap[j+1]>heap[j]) j++;//右孩子更大时j为右孩子下标
		if(heap[j]>heap[i]){
			swap(heap[i],heap[j]);//调整父子关系
			i=j;				  //调整后可能还需要调整 处理i,j了
			j=i*2;				  //注意每次初始i是欲调整的结点下标  而j是左孩子
		}else{
			//根就是最大的 直接break,不用调了
			break;//return也行  但是不能没有else分支 否则死循环
		}
	}
}

向上调整(O(logn))

//插入结点
//向上调整
//对heap数组在[low,high]范围内进行向上调整
//low一般置为1 即整棵树的根,high为欲向上调整的结点下标
void upAdjust(int low,int high){
	int i=high,j=i/2;//i为欲调整下标  j为父亲结点
	while(j>=low){//父亲在[low,j]范围内  low为1时就整棵树前面的范围
		if(heap[j]<heap[i])
			swap(heap[i],heap[j]);
			i=j;
			j=i/2;
		}else{
			break;
		}
	}
}

建堆(O(n))

//建堆  一开始已经数组heap中已经有了初始序列 建堆只是调整一下数组中元素的位置而已
void CreateHeap(){
	//从下往上 第一个非叶子结点开始 向上调整
	//n为堆元素个数 全局变量
	for(int i=n/2;i>=1;i--){
		downAdjust(i,n);
	}
}

删除结点(O(logn))

//删堆
//删除堆中一个结点  也要考虑调整问题,但是删除后该位置空缺如何调整呢?
//给出的策略是:最后一个元素来填空 然后n-- 然后向下调整被删结点位置即可
void DeleteHeap(int i){
	heap[i]=heap[n--];
	downAdjust(i,n);
}

插入结点(O(logn))

//插入结点 
void insert(int x){
	heap[++n]=x;
	upAdjust(1,n);
}

堆排序(O(nlogn))

void heapSort(){
	CreateHeap();//先要建立堆   即对非叶子结点都先分别做一次向下调整
	for(int i=n;i>1;i--){
		swap(heap[1],heap[i]);
		downAdjust(1,i-1);//heap[1]在i-1的范围内向下调整即可
	}
}

应用练习

Insertion or Heap Sort(A1098)

堆排序一般要从下标为1的数组开始

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值