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);//打印x
    cout << "q的y值:";
    Print2(q);//打印y
                                                                                     
    return 0;
}

 到此,我们今天的学习就结束了,感谢观看

\\\\٩( 'ω' )و ////

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值