C++queue,deque浅显了解及运用(信息学竞赛专用)

当然也可以不看 ==> 阅读我的文章前请务必先阅读此文章! 都是废话

目录

阅读文章须知

引言

队列(queue)

队列简介

​编辑

队列的创建

队列的操作

手写队列

双端队列(deque)

双端队列简介

双端队列的创建

双端队列的操作

 手写双端队列(原理)

写在最后


阅读文章须知

为了得到良好的阅读体验,请具备稍微完备的C++语法知识

在文章中出现类似[1]的标志,作者会在文章最后进行解释说明

注:只看蓝色加粗字加速阅读,红色加粗为误区或易错

引言

这篇文章接上篇文章C++vector浅显了解及运用继续讲解常用的数据结构,本篇讲解队列

队列(queue)

队列简介

队列是很常见的数据结构,顾名思义,就如日常排队,先进后出,因此push是从队尾进,pop是从队首出

队列的创建

queue<int> q;

表示创建了一个名字为q的队列,queue中的元素类型是int,元素类型是可以更改的,比如下面这个  

struct node
{
    int x, y, z;
};
queue<node> a;
queue<pair<int, string>> b;

以上代码中,queue a的元素类型是一个名为node的结构体,而queue b的元素类型是一个pair<int, string>类型(如果读者对于pair不熟悉的话,可以忽略此行)

在队列创建时,默认是空状态,即队列中没有任何元素

队列的操作

  • q.push(v) 表示将元素v插入队尾

  • q.pop() 表示将队首出队

  • q.front() 表示队首的元素 误区:q.front()只会返回队首元素而不会弹出队首!!!

  • q.back() 表示队尾的元素 同上

  • q.size() 表示队列的元素个数

  • q.empty() 返回一个bool型,false表示队列是空的,反之为true 

易错: 队列在pop前 千万千万一定一定 要检查q.empty()是否为false,当年因为这个我调了1个小时,见代码

queue<int> q;
cout << q.empty() << endl;
q.pop();
cout << q.empty() << endl;

 你猜输出的是什么?第一行毫无疑问是1,但是第二行是0!

手写队列

如果你想实现队列的遍历,或者取出更改非头尾的值,那么我强烈建议你手写队列,这并不是什么难事。如果使用迭代器遍历队列非常的麻烦,并且依然很难修改制定的值,下面是一份手写队列的代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5;
struct que  //将队列封装成一个结构体
{
    int q[N + 5]; //队列主体
    int head = 1, tail = 0; //头指针head,尾指针tail
    /*
    这里使用的head和tail可能与读者有所不同
    head指向队首,tail指向队尾
    因此当head == tail 时,队列中只有一个元素
    而 head > tail 时,队列中就没有元素了
    (见代码)

    有些读者的tail可能会指向队列尾元素的下一位
    因此push应该是q[tail++] = v
    back应该是q[tail - 1]
    empty应该是return head >= tail;
    */
    void push(int v) 
    {
        q[++tail] = v; //tail先向后移动一位,再将值放入tail的位置
        return ;
    }
    void pop()
    {
        head++; //将head像右移动一位,变相的将原来的队首踢出去
        return ;
    }
    int front()
    {
        return q[head];  //head指向的就是队首
    }
    int back()
    {
        return q[tail]; //同上
    }
    bool empty()
    {
        return head > tail;  //见上方段注释
    }
};
int main()  //队列的遍历
{
    //input
    for(int i = q.head; i <= q.tail; i++)
    {
        int key = q.q[i];
        //do something
    }
    //do something
}

 这看上去也非常简单,其实也不需要这么复杂,这些函数基本上都是一两行,建议直接放进代码中,调用函数也是需要时间成本的(我一同学就这么挂的,把函数展开就从TLE到AC了,当时他非常生气,把老师给吓了一跳),或者使用关键字inline,这里我们不细讲,下次我单独拉出来说

双端队列(deque)

与队列queue非常相似,因此这里很多内容一笔带过

双端队列简介

顾名思义,在队列的两个端点都可以进行操作

双端队列的创建

deque<int> q; //其他类型当然也可以

双端队列的操作

  • q.push_back(v)  将元素v加入队尾
  • q.push_front(v)  将元素v加入队首
  • q.pop_back()      弹出队尾
  • q.pop_front()      弹出队首
  • q.back()              返回队尾元素   误区:q.back()只会返回队首元素而不会弹出队首!!!
  • q.front()              返回队首元素   同上
  • q.empty()           同队列一样,返回一个bool类型,true表示队列空,反之为true
  • q.size()              返回队列中元素的个数

 手写双端队列(原理)

双端队列比队列难实现多了,细节非常的多,这里我只讲解原理,不贴代码了,因为我也不知道自己的细节处理是否正确。

先创建一个长度为n的数组,head和tail初始化

 队尾加入元素很简单,tail+1就行了

但如果是队首加入元素,就麻烦了,按道理是head--,然后将元素插入q[head],但是因为我喜欢下标从1开始,q[0]不是我想要的,或者说,我继续在队首加入元素,q[-1]更加不可能了,那么办法就是:从数组的最后开始往前加入

这里的n最好是数组极限大小,具体看题目要求,比如1e5+5

这里也不用担心tail和head会重合,因为你开的就是极限大小,比如题目要求数据范围是1e5,开1e5+5的数组怎么可能重合?

这里还比较好写,只需要写一个函数解决边界问题就行,比如

int real(int x)
{
    if(x == 0) return N + 3;
    if(x == N + 4) return 1;
}

 实现了下标从0变为N+3,从N+4变为1,之后每次指针改变都调用一下real函数

然后复杂的是判断empty,这个比较复杂,细节多,我不敢贴代码 

写在最后

本文章讲解queue和deque的用法,还是写了好多...,此处回忆之前以为一篇文章就把vector,queue,stack讲完,真是做白日梦,本来想扩展优先队列和单调队列的,但是写到这里太累了,所以下一篇文章两个选择,一是讲解单调队列和优先队列,二是讲解stack,投票选吧(虽然不会多,但是感谢投票的人)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值