首页 > 编程语言 >C++queue,deque浅显了解及运用(信息学竞赛专用)

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

时间:2024-07-26 19:28:17浏览次数:14  
标签:deque head 队列 队首 元素 C++ queue tail

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

目录

阅读文章须知

引言

队列(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,投票选吧(虽然不会多,但是感谢投票的人)

标签:deque,head,队列,队首,元素,C++,queue,tail
From: https://blog.csdn.net/latiao520/article/details/140506900

相关文章

  • asyncio Queue和Semaphore的结合使用
    importasyncio#假设这是你的大数据集large_data_set=range(1000000)#用1到1000000的数字模拟大数据集#任务队列task_queue=asyncio.Queue()#并发限制sem=asyncio.Semaphore(10)#任务处理函数asyncdefprocess_data(sem,q):whileTrue:#......
  • C#调用C++的dll方法
    C#调用C++的dll方法有时候用一些硬件厂家的库函数,厂家没有支持C#的,就只有C、C++语言,这个时候只能将C、C++编译成dll文件,然后用C#来调用这些接口。下面使用环境为vs2010,win32,x86C++打包成为dll首先创建一个win32的C++项目然后点击向导中的dll然后在这个文件中编写dll的函数......
  • C和C++执行线程的写法
    常见c/C++#include<windows.h>#include<iostream>DWORDWINAPIThreadProc(LPVOIDlpParam){std::cout<<"线程执行中,参数是:"<<(int)lpParam<<std::endl;return0;}intmain(){HANDLEhThread=CreateTh......
  • C++11特性总汇
    预定义宏211.预定义宏212.__func__宏返回当前所在函数或结构体名字213.#pragmaonce/_Pragma(“once”)该头文件只编译一次214.__VA_ARGS__变长参数宏定义#definePR(...)printf(__VA_ARGS__)215.宽窄字符串的连接支持longlongint类型22.longlongint......
  • c++11(4): 模版
    constexpr常量表达式函数:constexprintGetConst(){return1;}1):函数体只能有单一的return返回语句2):函数必须有返回值(不能为void)3):使用前必须已定义,即函数定义写在调用函数前面(放至后面则出错)4):return返回语句表达式中必须是一个常量表达式,且不能是运......
  • C++自学笔记17(const和mutable)
    const在之前的笔记中我们出现很多次constchar*name=“shaojie”,定义一个不可变指针存放字符串。不可变就来自const,表示“只读、常量”为什么需要它呢?我们需要一些东西不可被修改。const加数据变量#include<iostream>intmain(){constintMAX_AGE=99;M......
  • C++自学笔记18(成员初始化列表和初始化对象)
    成员列表初始化创建变量,并将其初始化是创建函数的必要部分。#include<iostream>#include<string>classEntity{private:std::stringm_name;public:Entity(){m_name="nothing"}Entity(conststd::string&name){......
  • C++ primer plus 第16章string 类和标准模板库, 函数符概念
    C++primerplus第16章string类和标准模板库,函数符概念C++primerplus第16章string类和标准模板库,函数符概念文章目录C++primerplus第16章string类和标准模板库,函数符概念16.5.1函数符概念程序清单16.15functor.cpp16.5.1函数符概念正如STL定......
  • C++ primer plus 第16章string 类和标准模板库, 函数对象
    C++primerplus第16章string类和标准模板库,函数对象C++primerplus第16章string类和标准模板库,函数对象文章目录C++primerplus第16章string类和标准模板库,函数对象16.5函数对象16.5函数对象很多STL算法都使用函数对象–也叫函数符(fiunctor)。......
  • 当你第一次用C++string的assign会遇到这种情况
    当你第一次用string的assign时,会发现有一点小区别,见以下代码:stringstr1;str1.assign("helloC++");cout<<str1<<endl;stringstr2;str2.assign(str1,5);cout<<str1<<endl;stringstr3;str3.assign("helloC++",5);cout<<......