STL容器 (priority_queue)

总结

1)优先队列,首先他是个队列,第二 有优先级,内部是堆维护,出队顺序可以为优先级从大到下 或者从小到大。

2)定义

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

 第2个参数是用来盛放堆的容器, 第三个参数决定优先级

less 越来越小, greater 越来越大。

3)结构体定义定义 ,可以重载运算符,

重运算符写到结构体内

struct fruit{
	string name;
	int price;
	friend bool operator < (fruit f1, fruit f2){
		return f1.price < f2.price;
	}
};

prioritt_queue<fruit> q;

写到结构体外

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

priority_queue<fruit, vector<fruit>, cmp> q;

加速度 + const + &

friend bool operator < (const fruit &f1, const fruit &f2){
	return f1.price > f2.price;
}
bool operator()(const fruit &f1, const fuit &f2){
	return f1.price > f2.price;
}

4)使用top() 函数前,必须用 empty()判断优先队列是否为空,否则可能因为队空出错

贴两篇大佬的文章:

坐在马桶上看算法_堆_优先队列(上)

坐在马桶上看算法_堆_优先队列(下)

什么是priority_queue?

priority_queue 又称为优先队列,底层是用来实现的,在优先队列中队首元素一定是当前队列中优先级最高的那一个,

桃子(优先级3)
梨子(优先级4)
苹果(优先级1)

出队顺序为 梨子(4)-》桃子(3) -》苹果(1)

当染我们可以在任何时候往优先队列里加入元素(push)。而优先队列底层的数据结构堆(heap)会随时进行调整,(优先队列里有一个堆,每次插入元素,这个堆就会自动调整),使得每次的队首元素都是优先级最大的

优先队列的应用

1)定义

要使用优先队列,应先添加头文件

#include<queue>
using namespace std;

其他写法给其他容器相同

priority_queue< typename > name;

2)priority_queue容器内元素的访问

和队列不一样的是,优先队列没有front()函数与back()函数,而只能通过top()函数来访问队首元素,(也可以说是堆顶元素)也就是优先级最高的元素。

#include<iostream>
#include<queue>
using namespace std;
int main (){
	priority_queue< int > q;
	q.push(3);
	q.push(4);
	q.push(1);
	cout << q.top() << endl;
	return 0;
}

他原本的优先级就是从大到小,也就是说他本来堆是一个大顶堆。

常用函数

1)push()

push(x)令x入队,时间复杂度,为O(logN),其中N为当前优先队列中的元素的个数,

2)top()

top()可以获得队首元素(堆顶元素)时间复杂度为 O(1)

3)pop()

pop()令队首元素出队,时间复杂度为O(logN),其中N为当前优先队列中元素的个数。

#include<iostream>
#include<queue>
using namespace std;
int main (){
	priority_queue< int > q;
	q.push(3);
	q.push(4);
	q.push(1);
	cout << q.top() << endl;
	q.pop();
	cout << q.top() << endl;
	return 0;
}

4)empty()

判空,若是空返回true,非空返回false。时间复杂度为O(1)。

5)size()

返回优先队列中元素的个数,时间复杂度为O(1)

priority_queue内元素的优先级的设置

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

就是 int  double, char等可以直接使用的数据类型,优先队列对它们的优先级设置一般是数字大的优先级最高,一次队首元素就是队列内元素最大那个(如果是char型,则字典序中最大的)。对基本数据类型来说,下面两种定义等价

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

可以发现,第二种定义方式尖括号内多了两个参数,一个是 vector<int>,另一个是less<int> 其中,vector<int>(第二个参数)填写的是来承载底层数据结构堆(heap)的容器,如果第一个参数是 double, char 型,则只需要填写 vector<double>,vector<char>就可以了, 而第三个参数, less<int> 则对第一个参数的比较类,less <int> 表示数字越大优先级越高。而greater<int> 表示数字越小优先级越大。

如果想让优先队列总是把最小的元素放在队首只需要进行以下定义

priority_queue<int, vector<int>, greater<int> > q;

下面例子

#include<iostream>
#include<queue>
using namespace std;
int main (){
	priority_queue<int, vector<int>, greater<int> > q;
	q.push(3);
	q.push(4);
	q.push(1);
	cout << q.top() << endl;
	q.pop();
	cout << q.top() << endl;
	return 0;
}

2)结构体优先级设置

最开始我们是不是看到一个水果的优先级定义

struct fruit{
	string name;
	int price;
};

现在我们希望按照水果的价格大小进行排序。

第一步我们需要 重载 < 。重载的意思就是对已有的运算符进行重新定义,就是说可以改变 < 的功能。

struct fruit{
	string name;
	int price;
	friend bool operator < (fruit f1, fruit f2){
		return f1.price < f2.price;
	}
};

我们在结构体内增加了一个函数,其中:friend 为友元友元函数大家可以百度一下,简单

函数重载

后面的 " bool operator < (fruit f1, fruit f2) " 对fruit类型的操作符,“ < " 进行了重载,(重载大于号编译器会出错,因为从数学来说只需要重载小于号,即 f1 > f2 等价与判断 f2 < f1 ,而f1 == f2 则等价与判断 ! (f1< f2) && ! (f1 > f2))

 这样我们就可以直接定义一个优先队列

priority_queue<fruit> q;

如果想以价格低的受过为优先级高则进需要把 return中的 小于号 改为 > 即可

struct fruit{
	string name;
	int price;
	friend bool operator < (fruit f1, fruit f2){
		return f1.price > f2.price;
	}
};

例子

#include<iostream>
#include<queue>
#include<string>
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;
}

诶诶诶诶,我好像发现了什么。这个对与 < 号的重载 好像和 sort中的cmp函数有些相似,他们的参数都是两个变量,函数内部都是return 了 true 或者 false.但是 效果好像正好相反,若果是  cmp  中 return < 号,那就是从小到大排列,其实在重载 < 号时也是这样,但是 优先队列定义后就直接相反了,因为优先队列本身默认规则就是优先级高的放在最前,不好记?

优先队列中的这个函数 与 sort中的cmp 函数的效果是相反的

那么可以跟sort中的cmp 写到结构体外呢? 当然OK

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

这种情况下我们就需要用之前定义优先队列的第二种方式 定义优先队列。

priority_queue<fruit, vector<int>, cmp> q;

我们只是把 greater<> 换成了 cmp

#include<iostream>
#include<queue>
#include<string>
using namespace std;
struct fruit{
	string name;
	int price;
}f1, f2, f3;
struct cmp {
	bool operator () (fruit f1, fruit f2){
		return f1.price < f2.price;
	}
};
int main (){
	priority_queue<fruit, vector<fruit>, cmp> 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;
}

同样,即便是基本数据类型或者其他STL容器,如(set), 也可以通过同样的方式来定义优先级

最后指出数据如果结构体内数据庞大,建议使用引用来提高效率。+ 上 “const ” 和 “&”

friend bool operator < (const fruit &f1, const fruit &f2){
	return f1.price > f2.price;
}
bool operator()(const fruit &f1, const fuit &f2){
	return f1.price > f2.price;
}

猜你喜欢

转载自blog.csdn.net/Harington/article/details/87874624
今日推荐