queue和priority_queue及其函数
目录
queue和priority_queue
priority_queue和queue的差别
queue
queue的成员函数
queue成员函数目录
front()
back()
push()
pop()
size()
swap()
emplace()
empty()
priority_queue
priority_queue的成员函数
priority_queue的成员函数目录
priority_queue的优先级设定
priority_queue的完整格式
优先级的自定义
queue和priority_queue
queue称为队列,而priority_queue称为优先级队列,两者除了基础功能相同且都遵循先进先出的规则外,两个对队列内元素处理方式不同
两个队列的使用都需要头文件queue
priority_queue和queue的差别
( 此处为引子,相关知识请查看本文章的相关知识点 )
代码演示:
#include <iostream>
#include <queue>
using namespace std;
void Print1(priority_queue<int> t)
{while (!t.empty()){cout << t.top() << " ";t.pop();}cout << endl;
}
void Print2(queue<int> t)
{while (!t.empty()){cout << t.front() << " ";t.pop();}cout << endl;
}
int main()
{cout << "两个都按顺序插入5,1,10,2" << endl;//设置一个队列queue<int> q2;//插入操作q2.push(5);q2.push(1);q2.push(10);q2.push(2);cout << "queue:";//上方写的打印函数Print2(q2);//设置一个优先队列priority_queue<int> q1;q1.push(5);q1.push(1);q1.push(10);q1.push(2);cout << "priority_queue:";Print1(q1);return 0;
}
运行结果:
可以看到,即使插入的元素以及顺序相同·,输出的元素顺序却不同,这就是优先级队列和队列的差别,优先级队列按照设定的优先级进行比较排序,而队列则不做处理
queue
queue名为队列,队列是一种容器适配器,专门设计用于在 FIFO (先进先出)中运行,其中元素插入到容器的一端并从另一端提取( 一端入,一端出 )
队列作为容器适配器实现,这些适配器是使用特定容器类的封装对象作为其基础容器的类,提供一组特定的成员函数来访问其元素。元素被推入特定容器的 “back”(队列尾) 并从其 “front” (队列头)弹出。
队列的图示:
补充知识(queue所有元素的打印):
队列无法像其他容器和数组一样直接访问中间任意下标的元素,只能访问到队列的头元素和队列的尾元素( 因为没有at函数和重载运算符 [ ] ,只有 front 和 back 函数访问头和尾 )
所以想要访问,就需要不断出队(移除队头元素)来对队头元素进行访问
代码演示:
#include <iostream>
#include <queue>
using namespace std;
int main()
{queue<int> q;//push为入队,在队尾加入一个元素q.push(1);q.push(2);q.push(3);//当前队列里有1,2,3这3个元素while (!q.empty())//判断是否为空{//开始对队头的元素进行打印cout << q.front() << " ";//pop为出队,移除第一个元素q.pop();}cout << endl;//我们可以测试队列是否为空//结果判断为空cout << "当前q是否为空:" << q.empty() << endl;return 0;
}
当然,上方代码存在问题,即为访问队列需要出队,这就导致了每次打印都会让队列清空,此时我们可以设置其为一个函数,并且通过拷贝的方式传给其函数,通过拷贝出来的队列进行出队打印操作将不会影响原队列
代码演示:
#include <iostream>
#include <queue>
using namespace std;void Print(queue<int> t)
{while (!t.empty()){cout << t.front() << " ";t.pop();}cout << endl;
}int main()
{queue<int> q;q.push(1);q.push(2);q.push(3);//当前队列里有1,2,3这3个元素//调用写好的打印函数Print(q);//判断为当前队列不为空cout << "当前q是否为空:" << q.empty() << endl;return 0;
}
可以看到,打印后我们判断原队列是否为空是给出了0,到此我们解决了队列元素的打印问题
queue的成员函数
queue成员函数目录
- front():访问队列中的第一个元素
- back():访问队列中的最后一个元素
- push():在队列尾部插入新元素
- pop():删除队列的队头元素
- size():返回队列的大小
- swap():将容器适配器中的内容进行交换
- emplace():在队列尾添加新元素
- empty():判断队列是否为空
front()
front()函数的作用:访问队列中的第一个元素
front()函数的格式:
- value_type& front();
- const value_type& front() const;
front()的代码演示将和下面的back()代码演示一起
back()
back()函数的作用:访问队列最后一个元素
back()函数的格式:
- value_type& back();
- const value_type& back() const;
代码演示:
#include <iostream>
#include <queue>
using namespace std;void Print(queue<int> t)
{while (!t.empty()){cout << t.front() << " ";t.pop();}cout << endl;
}int main()
{queue<int> q;q.push(10);q.push(55);q.push(75);cout << "原队列:";Print(q);//可对其进行访问cout << "front():" << q.front() << endl;cout << "back():" << q.back() << endl;//也可对其进行修改q.back() -= q.front();Print(q);return 0;
}
运行结果:
push()
push()函数的作用:在队列尾部插入新元素
push()函数的格式:
- void push (const value_type& val);
代码演示:
#include <iostream>
#include <queue>
using namespace std;void Print(queue<int> t)
{while (!t.empty()){cout << t.front() << " ";t.pop();}cout << endl;
}int main()
{queue<int> q;q.push(1); Print(q);q.push(2); Print(q);q.push(3);Print(q);return 0;
}
运行结果图:
pop()
pop()函数的作用:删除队列的队头元素
pop()函数的格式:
- void pop();
代码演示:
#include <iostream>
#include <queue>
using namespace std;void Print(queue<int> t)
{while (!t.empty()){cout << t.front() << " ";t.pop();}cout << endl;
}int main()
{queue<int> q;q.push(1); q.push(2); q.push(3);cout << "原队列:";Print(q);q.pop();cout << "pop操作后的队列:";Print(q);q.pop();cout << "pop操作后的队列:";Print(q);return 0;
}
运行结果图:
size()
size()函数的作用:返回队列的大小
size()函数的格式:
- size_type size() const;
代码演示:
swap()
swap()函数的作用:将容器适配器中的内容进行交换
swap()函数的格式:
- void swap (queue& x) noexcept(/*see below*/);
代码演示:
#include <iostream>
#include <queue>
using namespace std;void Print(queue<int> t)
{while (!t.empty()){cout << t.front() << " ";t.pop();}cout << endl;
}int main()
{queue<int> q1, q2;q1.push(10); q1.push(20); q1.push(30);q2.push(1); q2.push(2);cout << "原q1元素:";Print(q1);cout << "原q2元素:";Print(q2);q1.swap(q2);cout << "改后q1元素:";Print(q1);cout << "改后q2元素:";Print(q2);return 0;
}
运行结果图:
emplace()
emplace()函数作用:在队列尾添加新元素( 和push一样 )
emplace()函数的格式:
- template <class... Args> void emplace (Args&&... args);
代码演示:
#include <iostream>
#include <queue>
using namespace std;void Print(queue<string> t)
{while (!t.empty()){cout << t.front() << " ";t.pop();}cout << endl;
}
int main()
{queue<string> q;q.emplace("First");q.emplace("Second");q.push("Three");cout << "队列有:";Print(q);cout << "队列大小有:" << q.size() << endl;return 0;
}
运行结果图:
可以看到,emplace 和 push 的插入都是一样的
empty()
empty()函数作用:判断队列是否为空
empty()函数的格式:
- bool empty() const;
代码演示:
可以看到,我们在设置一个空队列后直接对其进行empty返回的是1,证明其为空队列
随后我们插入元素后进行empty返回的是0,证明其已经不为空
priority_queue
priority_queue称为优先级队列,优先级队列是一种容器适配器,专门设计使其第一个元素始终是它包含的元素中最大的,根据一些严格的弱排序标准
其是一个特殊的队列,类似于堆的队列,其的特殊在于用堆的特性,对队列进行自动排序
priority_queue的成员函数
priority_queue的成员函数目录
- top():返回队列头元素
- push():在队列尾部插入新元素
- pop():删除队列的队头元素
- size():返回队列的大小
- swap():将容器适配器中的内容进行交换
- emplace():在队列尾添加新元素
- empty():判断队列是否为空
priority_queue的所有函数都与普通的queue函数用法相同,只是priority_queue访问队头元素的函数改成了 top() 函数,所以不做演示
需要注意的是,priority_queue没有类似 back() 的函数,所以无法访问队列尾的元素
priority_queue的优先级设定
开头priority_queue和queue的差别时提到的priority_queue的优先级设定,这个设定决定了优先队列的排序方式,其默认为大堆(即从大到小),而我们也可以改变这个优先级的设定,让其按照需求进行排序
priority_queue的完整格式
priority_queue<int,vector<int>,less<int> >q;
- 第一个参数(int)为传入数据的类型
- 第二个参数(vector<int>)为存放的容器(需要存放在什么容器里,默认为vector)
- 第三个参数(less<int>)为优先级的设定(默认为less<int>(大堆,大到小),还有一个已经写好的设定为greater<int>(小堆,小到大),此外还可以自己设定优先级)
先来看下方案例,通过修改优先级,其排序的规则也进行了改变,输出结果也变得不同
优先级的自定义
相信你可能有疑问,明明已经给了大堆和小堆优先级的规则设定可以进行替换,为何还要自己写优先级的设定呢?
答案是当我们自定义类型且有多个参数在这类型中时,原先给的规则将不再适用
就如我们设定一个包含两个参数的自定义类型,一个表示年龄,一个表示编号,此时原先的队列规则就不知道比较年龄来排序还是比较编号排序
所以我们就需要自定义优先级的规则来给优先级队列进行排序
优先级定义样例:
//定义一个自定义类型node struct node {int x, y;//运算符重载,改变其比较大小的规则bool operator<(const node& b)const {return this->x > b.x;} };
代码解释:
- bool operator<(const node& b)const 就是优先级规则的定义,可通过重载运算符的方式,来比较返回所需要比较的参数
- const node& b 中的 b 只是引用,可随意修改
- 除 b 可修改之外bool operator<(const node& b)const 不作修改
- return 中间对比用的对比符可以改变,其就是决定大堆和小堆的关键因素
- this 为隐藏的指针
运算符重载后就自动调用相关的优先级规则,就像下方,只需要定义相关类型的队列时便开始调用,不需要替换掉原先的规则
代码运行图(完整代码在最下方):
下面为小堆的排序,此时返回为 this->x > b.x
上面优先级定义样例时说了,return的对比符可以改变,下面代码就改变了对比符,改变为了大堆,此时返回为 this->x < b.x
补充知识:
运算符重载还可以定义在自定义类型外,只是定义在自定义类型外时,没有了隐藏的this指针,需要主动上传两个参数,如下方代码
//定义一个自定义类型node
struct node
{int x, y;
};
bool operator<(const node& a, const node& b){return a.x < b.x;
}
完整代码:
#include <iostream>
#include <queue>
using namespace std;//定义一个自定义类型node
struct node
{int x, y;//运算符重载,改变其比较大小的规则//在自定义类型里进行重载bool operator<(const node& b)const {return this->x < b.x;}
};//在自定义类型外进行重载
//bool operator<(const node& a, const node& b) {
// return a.x < b.x;
//}//打印x
void Print1(priority_queue<node> t)
{while (!t.empty()){cout << t.top().x << " ";t.pop();}cout << endl;
}
//打印y
void Print2(priority_queue<node> t)
{while (!t.empty()){cout << t.top().y << " ";t.pop();}cout << endl;
}
int main()
{priority_queue<node> q;//自定义类型的输入//可以是//q.push({ x, y });//也可以是//node temp;//temp.x=1;temp.y=10;//q.push(temp);q.push({ 1, 10 });q.push({ 3, 20 });q.push({ 2, 30 });q.push({ 8, 50 });q.push({ 5, 15 });cout << "原先输入q的x值顺序为:1 3 2 8 5" << endl;cout << "原先输入q的y值顺序为:10 20 30 50 15" << endl;cout << "q的x值:";Print1(q);//打印xcout << "q的y值:";Print2(q);//打印yreturn 0;
}
到此,我们今天的学习就结束了,感谢观看
\\\\٩( 'ω' )و ////