六、priority_queue 的常见用法
priority_queue翻译为优先队列,其底层是用堆实现的,总是优先级最大的在队首。
头文件:#include <queue>
。除此之外还得在下面加上 using namespace std ;
1.定义
priority_queue<typyname> q;
2.访问
只能通过top()
来访问队首元素
注:每次必须先用empty()判断是够为空
3.常用函数
push(x) :元素x入队(O(logN))
pop(): 首元素出队 (O(logN))
empty():检测是否为空 (O(1))
size() : 返回元素个数(O(1))
clear() : 清空
4.优先级的设置
-
4.1 基本数据类型
此处指 int、double、char 等可直接使用的数据类型,优先队列对它们的优先级设置一般是数字大的优先级高
以下两种定义是等效的
priority_queue<int> q;
priority_queue<int, vector<int>, less<int> > q;
关于后面一种定义方式的说明: -
vector<int>
:承载底层数据结构堆的容器,若第一个参数是double、char ,则此处只需改为vector<double>、vector<char>
; -
less<int>
:表示数字大的优先级高,而greater<int>
表示数字小的优先级高
如果想要优先级队列总是把最小的元素放在队首,则如下定义
priority_queue<int, vector<int>, greater<int> > q;
-
4.2 结构体类型
注 : 其实基本数据类型也可按照结构体来写,只不过第三个参数有点区别(把less<int>
或者greater<int>
换成cmp,cmp为规定的优先级比较规则,下面会介绍)。
最重要的就是对小于号“<”进行重载,有两种方式:在结构体内部重载;在结构体外部重载。
注:只需要重载小于号,如果重载大于号的话会出现编译错误,大于号和等号可以等价转换成小于号表示。 -
构体内部重载
struct fruit
{
string name;
int price;
firend bool operator < (fruit f1, fruit f2)
{
return f1.price < f2.price; //价格高的优先级高
}
};
然后就可以直接定义使用了,其内部已满足给定的优先级比较规则。
priority_queue<fruit> q;
- 构体外部重载
去掉friend, 把小于号改成一对小括号
struct fruit
{
string name;
int price;
};
struct cmp
{
bool operator () (fruit f1, fruit f2)
{
return f1.price > f2.price; //价格低的优先级高
}
};
此时定义语句可以写为:
priority_queue<fruit, vector<fruit>, cmp > q;
注:若结构体内的数据较为庞大(例如出现字符串或数组),建议使用引用来提高效率,此时比较类的参数中需要加上 const 和 & :例如:
firend bool operator < (const fruit &f1, const fruit &f2)
{
return f1.price < f2.price; //价格高的优先级高
}
bool operator () (const fruit &f1,const fruit &f2)
{
return f1.price > f2.price; //价格低的优先级高
}
5.priority_queue 的使用场合
- 贪心问题,Dijkstra 算法
七、stack 的常见用法
stack 翻译为栈,先进后出。
头文件:#include <queue>
。除此之外还得在下面加上 using namespace std ;
1.定义
stack<typename >name;
2.访问
中能通过top()
函数访问栈顶元素
注:每次必须先用empty()判断是够为空
3.常用函数
push(x) :元素x入栈
top():获得栈顶元素【先用empty()判断是否为空】
pop():栈顶元素出栈 【先用empty()判断是否为空】
empty():判断栈是否为空
size() : 返回元素个数
注:栈没有清空函数。
八、pair 的常见用法
将两个元素绑在一起成为一个合成元素,又不想定义结构体时可以用 pair ,元素的类型时可以指定的。
头文件 #include<utility>
或者 #include<map>
注: 由于 map 的实现涉及 pair,故添加 map 头文件会自动添加 utility 头文件。
1.定义
pair<typeName1, typeName2> name;
如果需要在定义时进行初始化:pair<string, int> p("abcd", 5);
也可以是make_pair("abcd", 5);
2.访问
pair中只有两个元素,分别是first 和 second,按结构体的方式访问即可。
p.first; p.second;
3.常用函数
直接使用 ==、!=、<、<=、>、>= 比较大小
先以 first 大小为标准,当 first 相等时采取判别 second 的大小
4.作用
- 代替二元结构体及其构造时间,节省编码时间
- 作为map的键值对来进行插入
map<string,int> mp;
mp.insert(make_pair("abcd", 5));
mp.insert(pair<string, int> p("xyz", 10));
九、algorithm 头文件下的常用函数
- max()、min()、abs() :
· max(x,y)、min(x,y) 返回的是 x,y 中的最大值和最小值,需要注意的是,max() 和 min() 函数只能有两个参数(可以是浮点数),如果像求三个数 x,y,z 中的最大值可以写成:max(x,max(y,z)) 的格式。
· abs(x) 返回的是 x 的绝对值(x必须是整数)
注:求浮点数的绝对值可以用 math 头文件下的 fabs() 函数。
- swap(x,y) :交换 x , y 的值
- reverse(it,it2) : 将 [it,it2) 之间的元素反转 (abc 反转得到 cba) ,其中 it,it2 是指针或者是迭代器。
- next_permutation() : 得到一个序列在全排序中的下一个序列。例如,当 n==3 时的全排列为:123、132、213、231、312、321 。这样 123 的下一个序列就是 132。
使用的基本格式:
int a[10]={1,2,3};
do{
printf("%d %d %d",a[0],a[1],a[2]);
}while(next_permutation(a,a+3));//如果 next_permutation() 到达最后一个就会返回 false 。
输出结果:
123
132
213
231
312
321
- fill() : 可以把数组或者容器的某一个区间赋为某个相同的值,和 memset 不同(只建议赋值为 -1 和 0),这里的赋值可以是数组类型对应范围中的任意值。例如:
int a[5]={1,2,3,4,5};
fill(a,a+5,233);//将 a[0]~a[4] 均赋值为 233
- sort():排序(可以是基本类型的排序,也可以是结构体类型,容器类型),用法参见 考试排名问题
- lower_bound() 和 upper_bound():都是利用二分查找的方法在一个排好序的数组中进行查找的。
在从小到大的排序数组中:
lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。