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

一、队列(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> index;
    int num_size = num.size();
    if (num_size >= size && size >= 1){
        for (unsigned int i = 0; i < num_size; ++i){
            // 从后面依次弹出队列中比当前元素小的元素,
            // 同时也能保证队列首元素为当前窗口最大值下标
            while (!index.empty() && num[index.back()] <= num[i])
                index.pop_back();
            // 如果队首坐标对应的元素已经不在窗口中了(通过下标判断),
            // 则从当前窗口移出队首元素所在的位置
            while (!index.empty() && i - index.front() + 1 > size)
                index.pop_front();
            // 把每次滑动的元素下标加入队列
            index.push_back(i);
            // 当滑动窗口首地址i大于等于size时才开始写入窗口最大值
            if (i + 1 >= size)
                res.push_back(num[index.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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~青萍之末~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值