代码随想录笔记|C++数据结构与算法学习笔记-栈和队列(〇)|stack、queue、单调队列和优先级队列(priority_queue)、大顶堆和小顶堆

文章目录

  • stack容器
    • stack 基本概念
    • 常用接口
      • 构造函数
      • 赋值操作
      • 数据存取
      • 大小操作
  • queue容器
    • queue常用接口
      • 构造函数:
      • 赋值操作
      • 数据存取
      • 大小操作
  • 单调队列
    • 定义
    • 实现
      • 代码实现
    • 基本应用一:滑动窗口
      • 思路与算法
  • 优先级队列
    • 定义
      • 大顶堆(最大堆)、小顶堆(最小堆)
    • 实现
    • 基本操作
      • `push`和`emplace`
    • 基本应用一:滑动窗口
      • 思路与算法

stack容器

stack 基本概念

在这里插入图片描述
栈中只有顶端的元素才可以被外界使用,因此栈不允许有遍历行为。
栈中进入数据称为 — 入栈 push

栈中弹出数据称为 — 出栈 pop

常用接口

构造函数

  • stack<T> stk; //stack采用模板类实现, stack对象的默认构造形式
  • stack(const stack &stk); //拷贝构造函数

赋值操作

  • stack& operator=(const stack &stk); //重载等号操作符

数据存取

  • push(elem) //向栈顶添加元素
  • pop(); //从栈顶移除元素
  • top(); //返回栈顶元素

大小操作

  • empty; //返回堆栈是否为空
  • size(); //返回栈的大小

queue容器

在这里插入图片描述
队列容器允许从一端新增元素,从另一端移除元素

队列中只有队头和队尾才可以被外界使用,因此队列不允许有遍历行为

队列中进数据称为 — 入队 push

队列中出数据称为 — 出队 pop

queue常用接口

构造函数:

  • queue<T> que; //queue采用模板类实现,queue对象的默认构造形式
  • queue(const queue &que); //拷贝构造函数

赋值操作

  • queue& operator=(const queue &que); //重载等号操作符

数据存取

  • push(elem); //往队尾添加元素
  • pop(); //从队头移除第一个元素
  • back(); //返回最后一个元素
  • front(); //返回第一个元素

大小操作

  • empty(); //判断堆栈是否为空
  • size(); //返回栈的大小

单调队列

定义

单调队列也是一种常用的数据结构,但是在C++中并没有这类数据结构的实现。

单调队列的单调在于其内部的元素始终按照一定的单调性(递增或递减)排列。

始终按照是什么意思呢?即在每次加入或者删除元素时都保持序列里的元素有序,即队首元素始终是最小值或者最大值,这个功能非常重要,单调队列我们就是使用的这个功能
这种数据结构通常用于解决滑动窗口类型的问题,可以在 O(1) 时间复杂度内给出当前窗口的最大值或最小值。

实现

在实现时,需要保证队列的单调性:对于一个单调递增的队列,新进入队列的元素如果小于队尾的元素,那么队尾的元素将会被移除,直到队列单调或者队列为空。这样,队头元素始终是当前窗口的最小值。单调递减队列则相反
例子如下所示:

1: 5
2: 8
3: 8 2
4: 8 4
5: 8 4 1

详细过程如下:

1.首先队列里面没有元素,5加进去。
2.第二个元素8大于队尾的元素,所以5要弹出去,8加进去。保持队首最大
3.第三个元素2小于队尾元素8,可以加进去,变为8 2
4.4大于队尾元素2,2弹出,4小于8,8不弹出,4加进去
5.1小于队尾元素4,1加进去,最后队列为8 4 1

代码实现

单调队列的实现通常使用双端队列(deque),它允许在队列的前端和后端都可以进行元素的添加和删除操作

#include <deque>
#include <vector>template<typename T>
class MonotonicQueue {
private:std::deque<T> data;public:// Push an element on the queue. Remove elements smaller than the incoming one// to maintain the monotonic property.void push(T val) {while (!data.empty() && data.back() < val) {data.pop_back();}data.push_back(val);}// Return the maximum elementT max() const {return data.front();}// Pop an element from the queuevoid pop(T val) {if (!data.empty() && data.front() == val) {data.pop_front();}}
};

基本应用一:滑动窗口

文章链接
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

思路与算法

由于我们需要求出的是滑动窗口的最大值,如果当前的滑动窗口中有两个下标 ij,其中 i j 的左侧(i<j),并且 i 对应的元素不大于 j 对应的元素(nums[i]≤nums[j]),那么会发生什么呢?

当滑动窗口向右移动时,只要i还在窗口中,那么 j 一定也还在窗口中,这是 ij左侧所保证的。因此,由于 nums[j]的存在,nums[i] 一定不会是滑动窗口中的最大值了,我们可以将 nums[i]永久地移除

因此我们可以使用单调队列存储所有还没有被移除的下标。在单调队列中,这些下标按照从小到大的顺序被存储,并且它们在数组nums中对应的值是严格单调递减的。因为如果队列中有两个相邻的下标,它们对应的值相等或者递增,那么令前者为i,后者为 j,就对应了上面所说的情况,即 nums[i]会被移除,这就产生了矛盾。

当滑动窗口向右移动时,我们需要把一个新的元素放入队列中。为了保持队列的性质,我们会不断地将新的元素与队尾的元素相比较,如果前者大于等于后者,那么队尾的元素就可以被永久地移除,我们将其弹出队列。我们需要不断地进行此项操作,直到队列为空或者新的元素小于队尾的元素。

由于队列中下标对应的元素是严格单调递减的,因此此时队首下标对应的元素就是滑动窗口中的最大值。不过此时的最大值可能在滑动窗口左边界的左侧,并且随着窗口向右移动,它永远不可能出现在滑动窗口中了。因此我们还需要不断从队首弹出元素,直到队首元素在窗口中为止

链接:力扣官方题解

class Solution {
public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {int n = nums.size();deque<int> q;for (int i = 0; i < k; ++i) {while (!q.empty() && nums[i] >= nums[q.back()]) {q.pop_back();}q.push_back(i);}vector<int> ans = {nums[q.front()]};for (int i = k; i < n; ++i) {while (!q.empty() && nums[i] >= nums[q.back()]) {q.pop_back();}q.push_back(i);while (q.front() <= i - k) {q.pop_front();}ans.push_back(nums[q.front()]);}return ans;}
};

优先级队列

定义

优先级队列是一种抽象数据类型,它支持普通队列的基本操作,如入队和出队。不过,在优先级队列中,每个元素都有一定的“优先级”,出队操作会移除具有最高优先级的元素,而不是最先进入队列的元素。这种队列通常用于任务调度、带优先级的待办事项管理等场合。

在 C++ 中,优先级队列通常通过使用二叉堆(特别是大顶堆或小顶堆)来实现,而且标准库 <queue> 中已经提供了模板类 std::priority_queue

std::priority_queue 是一个容器适配器,它提供了某种特定服务策略(默认为最大堆)排序的队列

std::priority_queue 默认情况下使用一个 std::vector 作为底层容器,并使用 std::less 作为比较函数,这意味着元素是按照严格弱序(默认为大顶堆,即最大的元素总是在队列前端)排序的。

#include <iostream>
#include <queue>// 默认情况下,C++使用最大堆实现优先级队列
std::priority_queue<int> max_heap;// 使用最小堆实现优先级队列
std::priority_queue<int, std::vector<int>, std::greater<int>> min_heap;

那么问题来了,大顶堆和小顶堆又是什么呢?

大顶堆(最大堆)、小顶堆(最小堆)

堆的概念:堆具有结构性,也就是它是采用数组表示的完全二叉树。堆还具有有序性,也就是根节点大于子节点(或者小于子节点)

通过根节点大于子节点(或小于子节点),又可以将堆分为大顶堆和小顶堆

大顶堆:又称为最大堆,也就是树中所有父节点都要大于或等于子节点

小顶堆:又称为最小堆,也就是树中所有父节点都要小于或等于子节点

原文链接

实现

#include <iostream>
#include <queue>// 默认情况下,C++使用最大堆实现优先级队列
std::priority_queue<int> max_heap;// 使用最小堆实现优先级队列
std::priority_queue<int, std::vector<int>, std::greater<int>> min_heap;

基本操作

  • top:返回优先队列中具有最高优先级的元素。对于最大堆实现的优先队列,这将是最大的元素;对于最小堆实现,则是最小的元素。
  • push:向优先队列中添加一个元素。新元素的位置将根据其优先级与其他元素的比较结果来确定。
  • pop: 移除具有最高优先级的元素。在最大堆优先队列中,这通常是最大元素;在最小堆中,是最小元素。
  • empty: 检查优先队列是否为空。如果队列为空,返回 true;否则返回 false
  • size: 返回优先队列中元素的个数。
  • emplace:这个方法可以用来直接在优先队列的底层容器中就地构造一个新元素,这样可以避免额外的拷贝或移动操作。

pushemplace

push 方法相比,emplace 方法可以更高效地添加元素,特别是当队列中的对象较大或拥有非平凡的构造函数时。emplace 方法接受与元素构造函数相同的参数,并且在队列的适当位置直接构造对象。

#include <iostream>
#include <queue>
#include <string>int main() {std::priority_queue<std::string> pq;// 直接在优先队列中构造元素pq.emplace("orange");pq.emplace("strawberry");pq.emplace("apple");std::cout << "The top element is " << pq.top() << '\n';return 0;
}

在这个例子中,emplace 用于直接在优先队列中构造 std::string 对象。这避免了创建临时 std::string 对象并将它们推入队列的需要。这样不仅提高了效率,而且也使代码更加简洁。

基本应用一:滑动窗口

文章链接
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

思路与算法

对于「最大值」,我们可以想到一种非常合适的数据结构,那就是优先队列(堆),其中的大根堆可以帮助我们实时维护一系列元素中的最大值

初始时,我们将数组 nums的前 k 个元素放入优先队列中。每当我们向右移动窗口时,我们就可以把一个新的元素放入优先队列中,此时堆顶的元素就是堆中所有元素的最大值。然而这个最大值可能并不在滑动窗口中,在这种情况下,这个值在数组 nums中的位置出现在滑动窗口左边界的左侧。因此,当我们后续继续向右移动窗口时,这个值就永远不可能出现在滑动窗口中了,我们可以将其永久地从优先队列中移除

我们不断地移除堆顶的元素,直到其确实出现在滑动窗口中。此时,堆顶元素就是滑动窗口中的最大值。为了方便判断堆顶元素与滑动窗口的位置关系,我们可以在优先队列中存储二元组 (num,index),表示元素 num在数组中的下标为 index

class Solution {
public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {int n = nums.size();priority_queue<pair<int, int>> q;	//pair<int, int>将数组的值和对应的索引捆绑在一起for (int i = 0; i < k; ++i) {q.emplace(nums[i], i);}vector<int> ans = {q.top().first};for (int i = k; i < n; ++i) {q.emplace(nums[i], i);	//每次迭代将新元素和其索引加入优先级队列中。while (q.top().second <= i - k) {//在这个循环中,移除所有不再属于当前滑动窗口的元素//q.top().second 是队列顶部元素的索引,//如果它小于或等于 i - k,那么这个元素就不在窗口 [i - k + 1, i] 范围内,//因此需要将其从队列中弹出。q.pop();}ans.push_back(q.top().first);}return ans;}
};

链接:力扣官方题解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2906158.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

webserver--基于小根堆实现定时器,关闭超时的非活跃连接

计算机在工作时&#xff0c;我们打开多个网页&#xff0c;但是不使用的时候&#xff0c;系统自动会进入休眠模式&#xff0c;这样会更加省电&#xff0c;节省资源。同样的&#xff0c; 服务器在工作时&#xff0c;建立好连接后&#xff0c;即使你不用&#xff0c;他也会一直为你…

第22篇:异步复位D触发器

Q&#xff1a;本篇我们在基本D触发器中添加一个复位控制信号来实现带异步复位功能的D触发器。 A&#xff1a;带复位控制信号&#xff08;RST&#xff09;的D触发器&#xff0c;当RST为0时&#xff0c;输出Q为0&#xff1b;当RST为1时&#xff0c;Q取决于D和CLK的输入。 带复位…

MYSQL数字函数实操宝典:场景化SQL语句一网打尽

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》《MYSQL应用》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 MYSQL数字函数&#xff1a;不可不知的数据处理利器 文章目录 Part 1: 准备 &#x…

python pytz是什么

pytz模块常用于时区的转换&#xff0c;常常配合datetime一起使用。我们知道datetime除了data方法生成的时间是没有时区概念&#xff0c;其他如time、datetime等都是有时区概念&#xff0c;即指定了tzinfo信息。 >>> import datetime >>> datetime.datetime.n…

Nomad Web更新没有最快只有更快

大家好&#xff0c;才是真的好。 很长时间没介绍运行在浏览器中的Notes客户端即Nomad Web更新情况。 不用安装&#xff0c;直接使用&#xff0c;还可以完美地兼容适应各种操作系统&#xff0c;Nomad Web一定是Notes/Domino产品现在和将来重点发展的用户访问模式。 不过&…

comfyui 插件

Stable Diffusion ComfyUI 基础教程&#xff08;一&#xff09; ComfyUI安装与常用插件 - 知乎最近发现很多人在搬运我的文章&#xff0c;&#xff0c;&#xff0c;&#xff0c;那我也发 前言&#xff1a;相信大家玩 Stable Diffusion&#xff08;以下简称SD&#xff09;都是用…

超全面!和弦图(Chord diagram) 的绘制方法汇总~~

今天这篇推文给大家介绍一下和弦图(Chord diagram) 的绘制方法&#xff0c;具体包括的内容如下&#xff1a; 和弦图(Chord diagram)简介 和弦图(Chord diagram)绘制方法(RPython) 更多详细的数据可视化教程&#xff0c;可订阅我们的店铺课程&#xff1a; 和弦图(Chord di…

5.11 Vue配置Element UI框架

Vue配置Element UI框架 目录一、 概要二、 开发前准备1. 搭建Vue框架 三、 安装 Element UI1. 引入 Element UI 依赖2. 在 mian.js 中引入 Element UI 和相关样式&#xff1a;3. 按需引入(非必须, 可忽略)4. 简单构建一个主页面 目录 一、 概要 Element UI 是一个基于 Vue.js …

Java学习记录第十三天

面向对象编程 核心思想就是OOP&#xff08;面向对象编程&#xff09; 面向过程&面向对象 面向过程思想 步骤清晰简单&#xff0c;第一步做什么&#xff0c;第二步做什么... 面对过程适合处理一些较为简单的问题 面向对象思想 物以类聚&#xff0c;分类的思维模式&…

基于Java在线考试系统系统设计与实现(源码+部署文档)

博主介绍&#xff1a; ✌至今服务客户已经1000、专注于Java技术领域、项目定制、技术答疑、开发工具、毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅 &#x1f447;&#x1f3fb; 不然下次找不到 Java项目精品实…

WebGIS概述

1.地图组成 底图(Map): 所有信息的载体 图层(Layer):将不同地理信息分类形成的一个集合 要素(Feature):表示不同的地物 几何(Geometry): 信息的数据模型和抽象 2.地图容器Container 即在准备阶段所创建的指定了id的div对象&#xff0c;这个div将作为承载所有图层、点标记、矢量…

常用类(String)

目录 字符串相关的类1.1、String类的概述1.2、理解String的不可变性1.3、String不同实例化方式的对比1.4、String不同拼接操作的对比1.4.1、String使用陷阱 1.5、String的常用方法1.6、String与基本数据类型、包装类、char[]、byte[]的转换1.7、StringBuffer和StringBuilder的介…

EasyBoss ERP上线实时数据大屏,Shopee本土店铺数据实时监测

近日&#xff0c;灵隐寺PPT汇报用上数据大屏疯狂刷屏&#xff0c;有做东南亚本土电商的老板发现这种数据大屏的模式可以很好地展现店铺运营状况。 所以就有老板来问&#xff1a;EasyBoss能不能也上线实时数据大屏的功能&#xff1f;没问题&#xff01;立马安排&#xff01; 要有…

鸿蒙OS开发实例:【应用级别文件浏览器】

介绍 HarmonyOS的沙盒机制完全屏蔽了应用对手机公共存储空间的访问&#xff0c;安全性提高已不言而喻。 本篇文章的主要目的是为了能通过一个简单工具&#xff0c;可视化的让一个新手能相对轻松的学习文件&数据存储。HarmonyOS 应用开发工具DevEco Studio也没有提供读取存…

.NET CORE 分布式事务(二) DTM实现TCC

目录 引言&#xff1a; 1. TCC事务模式 2. TCC组成 3. TCC执行流程 3.1 TCC正常执行流程 3.2 TCC失败回滚 4. Confirm/Cancel操作异常 5. TCC 设计原则 5.1 TCC如何做到更好的一致性 5.2 为什么只适合短事务 6. 嵌套的TCC 7. .NET CORE结合DTM实现TCC分布式事务 …

【Linux多线程】线程的同步与互斥

【Linux多线程】线程的同步与互斥 目录 【Linux多线程】线程的同步与互斥分离线程Linux线程互斥进程线程间的互斥相关背景概念问题产生的原因&#xff1a; 互斥量mutex互斥量的接口互斥量实现原理探究对锁进行封装(C11lockguard锁) 可重入VS线程安全概念常见的线程不安全的情况…

查询优化-提升子查询-UNION类型

瀚高数据库 目录 文档用途 详细信息 文档用途 剖析UNION类型子查询提升的条件和过程 详细信息 注&#xff1a;图片较大&#xff0c;可在浏览器新标签页打开。 SQL: SELECT * FROM score sc, LATERAL(SELECT * FROM student WHERE sno 1 UNION ALL SELECT * FROM student…

halcon例程学习——ball.hdev

dev_update_window (off) dev_close_window () dev_open_window (0, 0, 728, 512, black, WindowID) read_image (Bond, die/die_03) dev_display (Bond) set_display_font (WindowID, 14, mono, true, false) *自带的 提示继续 disp_continue_message (WindowID, black, true)…

Redis桌面客户端

3.4.Redis桌面客户端 安装完成Redis&#xff0c;我们就可以操作Redis&#xff0c;实现数据的CRUD了。这需要用到Redis客户端&#xff0c;包括&#xff1a; 命令行客户端图形化桌面客户端编程客户端 3.4.1.Redis命令行客户端 Redis安装完成后就自带了命令行客户端&#xff1…