队列及其应用(滑动窗口求最大值)

一、队列(queue)

1、队列的特点

  队列(Queue)与栈一样,是一种线性存储结构,它具有如下特点:

【Note】:
(1)队列中的数据元素遵循“先进先出”(First In First Out)的原则,简称FIFO结构。
(2)在队尾添加元素,在队头删除元素。

  队列在栈在计算机中应用相当广泛,包括广度优先搜索、CPU的作业调度、缓冲区等等。

2、队列的相关概念

(1)队头( front() )与队尾( back() ): 允许元素插入的一端称为队尾,允许元素删除的一端称为队头。
(2)入队( push_back() ):队列的插入操作。
(3)出队( pop_front() ):队列的删除操作。
这里写图片描述

二、环形队列

  如果使用顺序表作为队列的话,当处于右图状态则不能继续插入新的队尾元素,否则会因为数组越界而导致程序代码被破坏。
这里写图片描述

  由此产生了由链表实现的循环队列,只有队列未满时才可以插入新的队尾元素,从而解决了无法判断队列是否溢出的问题。
这里写图片描述

【Note】:
(1)普通队列判断空或满:front == rear, rear == max_size - 1;
(1)循环队列判断空或满:front == rear, (rear + 1) % max_size == 0;

三、双端队列(deque)

  双端队列是一种可以在两端做插入和删除操作的队列,而且插入和删除的速度很快;但是在内部进行插入和删除操作,性能不及list。

这里写图片描述

(1)队头: front() , 队尾:back()
(2)队头入队:push_front() , 队尾入队:push_back()
(3)队头出队: pop_front() , 队尾出队:pop_back()

四、队列的应用之滑动窗口求最大值

  有一个整型数组 arr 和一个大小为 w 的窗口从数组的最左边滑到最右边,窗口每次向右边滑一个位置。 返回一个长度为n-w+1的数组res,res[i]表示每一种窗口状态下的最大值。 以数组为[4,3,5,4,3,3,6,7],w=3为例。
因为第一个窗口[4,3,5]的最大值为5,第二个窗口[3,5,4]的最大值为5,第三个窗口[5,4,3]的最大值为5。第四个窗口[4,3,3]的最大值为4。第五个窗口[3,3,6]的最大值为6。第六个窗口[3,6,7]的最大值为7。
所以最终返回[5,5,5,4,6,7]。

给定整形数组arr及它的大小n,同时给定w,请返回res数组。保证w小于等于n,同时保证数组大小小于等于500。

测试样例:
[4,3,5,4,3,3,6,7],8,3

返回:
[5,5,5,4,6,7]

1、思路

  我们用一个双向队列deque来解决该问题。

1. 如果新来的值比队列尾部的数小,那就追加到后面,因为它可能在前面的最大值划出窗口后成为最大值。

2. 如果新来的值比尾部的大,那就删掉尾部(因为有更大的在后面,所以它不会成为最大值,划出也是它先划出,不影响最大值),再追加到后面,循环下去保证次最大值总是紧邻队头元素。

3. 如果追加的值比的索引跟队列头部的值的索引超过窗口大小,那就删掉头部的值

4. 其实这样每次队列的头都是最大的那个。

2、demo

#include <bits/stdc++.h>
using namespace std;

vector<int> fun(const vector<int> &vec, const int &n, const int &w)
{
    vector<int> res;
    deque<int> dq;
    for (int i = 0; i<n; ++i)
    {
        if (dq.empty())
            dq.push_back(vec[i]);//从队尾插入元素
        else
        {
            while (!dq.empty())
            {
                if (dq.back() >= vec[i])
                    break;
                else//如果队尾元素<下一个元素,则不断删除队尾元素(保证次最大值总是紧邻队头元素)
                    dq.pop_back();
            }
            dq.push_back(vec[i]);//如果队尾(有时候也是队头)元素>=下一个元素加入队尾
        }
        if (dq.size() >= w)//当前队列元素>=窗口大小,删除队头元素
            dq.pop_front();
        if (i >= w - 1)
            res.push_back(dq.front());//队头元素是滑动窗口的最大值
    }
    return res;
}

int main(int argc, char const *argv[])
{
    vector<int> v1 = { 4,3,5,3,4,3,6,7 };
    int a = 8;
    int b = 3;
    vector<int> v2 = fun(v1, a, b);
    for (const auto v : v2)
        cout << v << endl;
    system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/daaikuaichuan/article/details/80315834