一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情。
队列(queue)
特点: 先进先出 (和我们日常生活中的排队是一样的)。
使用规则
- 头文件
#include <queue> - 队列的声明(
que为对象,名字自定义):queue<int> que;queue<string> que;queue<node> que;
- 队列常用操作
que.front():返回 queue 中第一个元素的引用。如果 queue 为空,返回值是未定义的。que.back():返回 queue 中最后一个元素的引用。如果 queue 为空,返回值是未定义的。que.push():在 queue 的尾部添加一个元素。que.pop():删除 queue 中的第一个元素。que.size():返回 queue 中元素的个数。que.empty():判断队列是否为空,如果 queue 中没有元素的话,返回 true。
小结
在学习优先队列和双向队列之前,需要掌握队列的使用方法。因为他们彼此之间的使用规则都比较类似,而队列作为他们中最简单的数据结构,所以放在开头学习。
优先队列(priority_queue)
特点:队列中的元素按照优先级顺序进行排序。(在队列的基础上增加了优先级顺序)
时间复杂度: 插入和删除操作的时间复杂度为
n次插入删除操作的时间复杂度为
使用规则
- 头文件
#include <queue> - 优先队列的声明(
que为对象,名字自定义):priority_queue<node> que; //基础类型,默认是大顶堆priority_queue<int, vector<int>, less<int> > que; //大顶堆,大元素在上priority_queue<int, vector<int>, greater<int> > que; //小顶堆,小元素在上
需要注意的是优先队列的声明:
less翻译为较少的,但是在优先队列的声明中表示大顶堆greater翻译为更大的,但是在优先队列的声明中表示小顶堆
- 优先队列常用操作
que.top():访问队头元素。
优先队列中访问头元素用
top()方法,对比普通队列中用的是front()方法。que.push(x):将元素x放入队列。
优先队列会将放入的元素自动根据优先级进行排序。
que.pop():将队首元素弹出(删除)。que.size():返回队列大小(也就是队列中的元素个数)。que.empty():判断队列是否为空,如果队列为空,返回true。
结构体重载
对结构体 struct 元素进行自定义优先级。当我们将结构体元素放入优先队列或者 sort() 函数中进行排序时需要对结构体元素赋予一定的优先级顺序,这时候就可以在结构体元素中自定义重载,也就是让结构体遵从结构体内某元素的优先级进行排序。
结构体重载定义的模板
struct node{
int u, v;
friend bool operator < (node a , node b){
if(a.u == b.u) return a.v > b.v;
return a.u > b.u;
//优先队列中的排序大小与结构体里重载的符号相反
//sort()函数中的排序大小与结构体里重载的符号一致
}
};
这里需要注意
return语句中的>和<符号:
- 优先队列中的优先级大小与结构体里重载的符号相反(
>符号表示小顶堆,按照从小到大排序)- sort()函数中的排序大小与结构体里重载的符号一致(
>符号表示按照从大到小排序)
声明和使用
- 结构体重载的优先队列声明方式:
priority_queue<node> que;
只需要按照优先队列的声明方式即可,因为在
node结构体里以及自定义重载了结构体元素的排序优先级。
sort()函数对结构体数组进行排序:sort(node, node + n);(node表示开始的位置,node + n表示结束的位置,n表示结构体数组大小,这里表示对node[0]到node[n - 1]进行排序)
注意
sort()函数需要包含头文件#include <algorithm>
sort()函数排序的时间复杂度为
sort()函数还可以使用cmp传参进行自定义排序优先级:sort(node, node + n, cmp);static bool cmp(node a, node b){ if(a.u == b.u) return a.v > b.v; return a.u > b.u; }自定义
sort()函数中的cmp需要加static声明。在class类中的sort()函数的参数cmp,定义时要声明为static,static静态成员函数不用加对象名,就能直接访问函数(这也是静态成员函数的一大优点)
sort() 函数使用标准库函数进行定义排序顺序:
升序(默认):sort(begin,end,less<data-type>())
降序:sort(begin,end,greater<data-type>())
双向队列(deque)
在上述的队列数据结构中我们只能对队首元素进行弹出(删除)操作,对队尾进行插入(添加)操作,如果我们想对队首进行插入或者队尾进行删除操作的话,队列时无法完成的,所以有了双向队列,在双向队列中,可以对双向队列的头部和尾部进行插入删除操作。
时间复杂度: 插入和删除操作的时间复杂度为
n次插入删除操作的时间复杂度为
使用规则
-
头文件
#include <deque> -
优先队列的声明(
deq为对象,名字自定义):deque<int> deq;deque<double> deq;deque<node> deq;
-
双向队列常用操作:
deq.back():访问队尾元素。deq.front():访问队首元素。deq.clear():清空双向队列。
这里对比C++中的队列
queue自身是不支持clear操作的,但是双端队列deque是支持clear操作的。那么要清空队列queue我们只能通过while循环来清空队列。queue<int> que;//头文件 #include <queue> deque<int> deq;//头文件 #include <deque> while(que.size()) que.pop();//清空队列que deq.clear();//清空双向队列deq.size():返回双向队列的大小(也就是双向队列中元素的个数)deq.empty():判断双向队列是否为空,为空返回truedeq.push_front(x):在双向队列头部插入元素x。deq.push_back(x):在双向队列尾部插入元素x。deq.pop_front():弹出(删除)双向队列头部元素。deq.pop_back():弹出(删除)双向队列尾部元素。deq.resize(x):改变双向队列的大小,也就使得队列中元素个数为x。
总结
以上就是队列、优先队列和双向队列的数据结构的介绍和总结,其中在介绍优先队列时加入了结构体重载的介绍。
使用时需要注意对应的队列操作时间复杂度,结构体重载的用法常常用在 sort 函数和优先队列中,往往需要对结构体中某个成员变量进行排序时用到。
结束语
生活是讲究节奏的。该奋起直追时,就全力以赴;该养精蓄锐时,就从容修养。流流汗,休息时更加惬意;歇歇脚,再出发精神百倍。