第二次课优先队列和重载运算符

堆是一个完全二叉树实现的,主要分为大根堆和小根堆,只有根节点有意义

插入(up):o(log n) 

删除(down):o(log n) 删除根节点

大根堆

例子:

子节点比父亲节点小,根节点最大

                               9
                            /     \
                           6        8
                          / \      / \
                          5  3    7   0
                         / \ /
                        4  1 2
             

 插入:

在最后一行第一个空余的位置插入,如果父亲节点比这个插入的节点小,就进行交换,

如果满足大根堆得条件或到达堆顶,就停止操作

删除:

删除根节点,将最后一从左往右数最后一个元素移动到根节点上,如果此时满足大根堆得特点,就说此时是一个大根堆,如果不满足,就将它的两个子节点中较大的哪个子节点进行交换,重复上述操作,若满足大根堆得特点,就停止操作

小根堆

子节点比父亲节点大,根节点最小

例子:

                                   1
                                /      \
                                2       3
                               / \     /  \
                              4   5   6    7
                     

 插入:

在最后一行第一个空余的位置插入,如果父亲节点比这个插入的节点大,就进行交换,

如果满足小根堆得条件或到达堆顶,就停止操作

删除:

删除根节点,将最后一从左往右数最后一个元素移动到根节点上,如果此时满足小根堆的特点,就说此时是一个小根堆,如果不满足,就将它的两个子节点中小的那个子节点进行交换,重复上述操作,若满足小根堆得特点,就停止操作

优先队列

在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出的行为特征。

优先队列底层是堆实现的,也分为大根堆和小根堆

降序优先队列:priority_queue<int> q; 大根堆
升序优先对列priority_queue<int,vector<int>,greater<int> > q; 小根堆 
q.push(x) 入队
q.top() 返回队首元素
q.pop() 队首元素出队
q.empty() 判断是否为空
q.size() 获取大小 

重载运算符

运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,简化操作 让已有的运算符 适应不同的数据类型,通常用于结构体

例子:

bool operator<(const node&b) const {
        return val>b.val;
 }

构造函数

对结构体进行赋值

例子:

struct node{
	int x,y;
    node(int a,int b,int c){
    	x=a;y=b;val=c;
	}
};

例题

序列合并

题目描述

有两个长度都是N的序列A和B,在A和B中各取一个数相加可以得到N^2​​个和,求这个N^2和中最小的N个。

输入描述

第一行一个正整数N;

第二行N个整数A​i​​

第三行N个整数B​i​​

输出描述

输出仅一行,包含N个整数,从小到大输出这N个最小的和,相邻数字之间用空格隔开。

输入样例

3

2 6 6

1 4 8

输出样例

3 6 7

思路一

创造一个结构体,分为三个值,x为a数组的下标,y为b数组的下标,val为a[i]+b[j]的和,将a数组和b数组从小到大排序

创立一个大根堆,将{1,1,a[1]+b[1]}放入队列,每次输出最小的(此时a[1]+b[1]肯定是最小的,因为排序过).

建立一个map去重,进行n次循环如果还没有被标记过,就将{x+1,y,a[x+1]+b[y]}或{x,y+1,a[x],b[y+1]}放入队列

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e7+10;
int a[maxn],b[maxn];
struct node{
	int x,y;
	long long val;
	bool operator<(const node&b) const {
        return val>b.val;
    }
    node(int a,int b,int c){
    	x=a;y=b;val=c;
	}
};
map<pair<int,int>,int> mp;
priority_queue<node> q;
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>b[i];
    sort(a+1,a+n+1);
    sort(b+1,b+n+1);
	q.push({1,1,a[1]+b[1]});
	while(n--){
		int x=q.top().x,y=q.top().y;
		cout<<q.top().val<<" ";
		q.pop();
		if(mp[{x+1,y}]==0){
			q.push({x+1,y,a[x+1]+b[y]});
			mp[{x+1,y}]=1;
		}
		if(mp[{x,y+1}]==0){
			q.push({x,y+1,a[x]+b[y+1]});
			mp[{x,y+1}]=1;
		}
	}
	return 0;
}
思路二  

时间复杂度O(n^2)

先枚举n^2个两个数的和,排序后,创造一个大根堆,若大根堆中的元素个数小与n,

将a[i]+b[j]的值入队,如果不满足,a[i]+b[j]如果小与队首元素,将队首元素出队,

并将a[i]+b[j]入队,有如果不小于,直接退出循环,因为此时已经排序过。

#include <bits/stdc++.h>
using namespace std;
priority_queue<long long> q;
const int maxn=1e7+10;
int a[maxn],b[maxn],c[maxn];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>b[i];
	sort(a+1,a+n+1);
	sort(b+1,b+n+1);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			int x=a[i]+b[j];
			if(q.size()<n) q.push(x);
			else{
				if(x<q.top()){
					q.pop();
					q.push(x);
				}
				else break;
			}
		}
	}
	int k=n,o=0;
	while(k--){
		c[++o]=q.top();
		q.pop();
	}
	for(int i=o;i>=1;i--){
		cout<<c[i]<<" ";
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值