【C++初阶】介绍stack_queue及OJ题

news2024/12/22 3:28:22

介绍stack_queue及OJ题

  • 前言
  • 一、简单了解
    • 1、stack
    • 2、queue
  • 二、OJ题(前三个栈,第四、五个队列)
    • 1、最小栈
      • (1)题目描述
      • (2)解题思路
      • (3)解题代码
    • 2、栈的压入、弹出序列
      • (1)题目描述
      • (2)解题思路
      • (3)解题代码
    • 3、逆波兰表达式求值
      • (1)题目描述
      • (2)解题思路
      • (3)补充小知识:中缀转后缀运算
        • i、场景一:最简单
        • ii、场景二:出现括号
        • iii、场景三:连续比较
      • (4)解题代码
    • 4、二叉树的层序遍历1
      • (1)题目描述
      • (2)解题思路
      • (3)解题代码
    • 5、二叉树的层序遍历2
      • (1)题目描述
      • (2)解题思路
      • (3)解题代码
  • 三、容器适配器
    • 1、什么是适配器
    • 2、模拟实现stack容器适配器
    • 3、模拟实现queue容器适配器
    • 4、介绍deque(外强中干)
      • (1)deque的原理介绍
      • (2)了解一下vector和list的优势和缺陷
      • (3)中控数组概念
        • i、与vector比较
        • ii、与list比较
      • (4)简单介绍deque的底层
      • (5)deque缺陷
      • (6)为什么选择deque作为stack和queue的底层默认容器


前言

简单的stack_queue操作起来和模拟起来很简单,但是其中蕴含的逻辑需要仔细甄别,特别是要根据STL库函数中的代码进行理解起来就稍微有些难以理解,所以我们需要一边利用着源代码一边利用着数据结构的知识进行操作理解。


一、简单了解

1、stack

在这里插入图片描述

在这里插入图片描述

#include<iostream>
#include<stack>
#include<queue>
using namespace std;

// stack
int main()
{
	stack<int> st;
	st.push(1);
	st.push(2);
	st.push(3);
	st.push(4);

	while (!st.empty())
	{
		cout << st.top() << " ";
		st.pop();
	}
	cout << endl;

	return 0;
}

2、queue

在这里插入图片描述

在这里插入图片描述

#include<iostream>
#include<stack>
#include<queue>
using namespace std;
// queue
int main()
{
	queue<int> q;
	q.push(1);
	q.push(2);
	q.push(3);
	q.push(4);

	while (!q.empty())
	{
		cout << q.front() << " ";
		q.pop();
	}
	cout << endl;

	return 0;
}

二、OJ题(前三个栈,第四、五个队列)

1、最小栈

(1)题目描述

leetcode最小栈
在这里插入图片描述
接口函数:

class MinStack {
public:
    MinStack() {

    }
    
    void push(int val) {

    }
    
    void pop() {

    }
    
    int top() {

    }
    
    int getMin() {

    }
    
};

(2)解题思路

利用两个栈,一个栈是正常栈,另一个栈是最小栈,正常栈里面存放的是所有的值,最小栈里面存放的是与底下元素进行比较,较小的存放进去,较大的不存放。

在这里插入图片描述

(3)解题代码

class MinStack {
public:
    MinStack() {}
    
    void push(int val) {
        _st.push(val);
        if(_minst.empty() || val <= _minst.top())
        {
            _minst.push(val);
        }
    }
    
    void pop() {
        if(_minst.top() == _st.top())
        {
            _minst.pop();
        }
        _st.pop();
    }
    
    int top() {
        return _st.top();
    }
    
    int getMin() {
        return _minst.top();
    }
private:
    stack<int> _st;
    stack<int> _minst;
};

2、栈的压入、弹出序列

(1)题目描述

牛客网栈的压入、弹出序列
在这里插入图片描述

(2)解题思路

模拟!

在这里插入图片描述

在这里插入图片描述

(3)解题代码

class Solution {
public:
    bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {
        stack<int> st;
        int pushi = 0;
        int popi = 0;
        while(pushi < pushV.size())
        {
            st.push(pushV[pushi++]);
            // 不匹配
            if(st.top() != popV[popi])
            {
                continue;
            }

            // 匹配
            else 
            {
                while(!st.empty() && st.top() == popV[popi])
                {
                    st.pop();
                    ++popi;
                }
            }
        }
        return st.empty();
    }
};

3、逆波兰表达式求值

(1)题目描述

leetcode逆波兰表达式求值

在这里插入图片描述

(2)解题思路

利用后缀进行计算如下:
在这里插入图片描述

(3)补充小知识:中缀转后缀运算

在这里插入图片描述

i、场景一:最简单

在这里插入图片描述

ii、场景二:出现括号

在这里插入图片描述

iii、场景三:连续比较

在这里插入图片描述

(4)解题代码

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> st;

        for(auto& str : tokens)
        {
            if(str == "+" || str == "-" || str == "*" || str == "/")
            {
                int right = st.top();
                st.pop();

                int left = st.top();
                st.pop();

                switch(str[0])
                {
                    case '+':
                    {
                        st.push(left+right);
                        break;
                    }
                    case '-':
                    {
                        st.push(left-right);
                        break;
                    }
                    case '*':
                    {
                        st.push(left*right);
                        break;
                    }
                    case '/':
                    {
                        st.push(left/right);
                        break;
                    }
                }
            }
            else
            {
                st.push(stoi(str));
            }
        }

        return st.top();
    }
};

4、二叉树的层序遍历1

(1)题目描述

leetcode二叉树的层序遍历

在这里插入图片描述

(2)解题思路

加一个LevelSize,记录每一层的数量,出一个往外减减,需要特别注意的是出一个进其二叉树底下的结点(两个或一个)。
在这里插入图片描述

(3)解题代码

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> vv;
        queue<TreeNode*> q;
        int LevelSize = 0;

        if(root)
        {
            q.push(root);
            LevelSize = 1;
        }

        while(!q.empty())
        {
            vector<int> v;
            for(int i = 0; i < LevelSize; ++i)
            {
                TreeNode* front = q.front();
                q.pop();

                v.push_back(front->val);

                if(front->left)
                    q.push(front->left);
                if(front->right)
                    q.push(front->right);
            }
            vv.push_back(v);
            LevelSize = q.size();
        }
        return vv;

    }
};

5、二叉树的层序遍历2

(1)题目描述

leetcode二叉树的层序遍历2

在这里插入图片描述

(2)解题思路

只用加一个reverse即可,因为是从下往上遍历的。

(3)解题代码

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
                vector<vector<int>> vv;
        queue<TreeNode*> q;
        int LevelSize = 0;

        if(root)
        {
            q.push(root);
            LevelSize = 1;
        }

        while(!q.empty())
        {
            vector<int> v;
            for(int i = 0; i < LevelSize; ++i)
            {
                TreeNode* front = q.front();
                q.pop();

                v.push_back(front->val);

                if(front->left)
                    q.push(front->left);
                if(front->right)
                    q.push(front->right);
            }
            vv.push_back(v);
            LevelSize = q.size();
        }

        reverse(vv.begin(), vv.end());
        return vv;
    }
};

三、容器适配器

1、什么是适配器

适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。

在这里插入图片描述
在这里插入图片描述

deque后续介绍。

2、模拟实现stack容器适配器

stack.h:

#include<iostream>
#include<vector>
#include<list>
namespace JRH
{
	// 容器适配器
	template<class T, class Container = deque<T>>
	class stack
	{
	public:
		// 插入 尾插
		void push(const T& x)
		{
			_con.push_back(x);
		}
		// 删除 尾删
		void pop()
		{
			_con.pop_back();
		}
		// 取栈顶元素
		T& top()
		{
			return _con.back();
		}
		// 输出个数
		size_t size()
		{
			return _con.size();
		}
		// 判空
		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
	
	void test_stack1()
	{
		stack<int, vector<int>> st1;
		st1.push(1);
		st1.push(2);
		st1.push(3);
		st1.push(4);
		while (!st1.empty())
		{
			cout << st1.top() << " ";
			st1.pop();
		}
		cout << endl;
		stack<int, list<int>> st2;
		st2.push(1);
		st2.push(2);
		st2.push(3);
		st2.push(4);
		while (!st2.empty())
		{
			cout << st2.top() << " ";
			st2.pop();
		}
		cout << endl;
	}
}

test.cpp:

#include<iostream>
#include<vector>
#include<list>
#include<queue>
#include<stack>
using namespace std;

#include"stack.h"
#include"queue.h"

int main()
{
	JRH::test_stack1();
	//JRH::test_queue();
	return 0;
}

知识点:为什么using namespace std放在比stack.h上面?
在这里插入图片描述
这是因为编译器进行编译的时候是往上寻找,而上面正好是已经展开std的全局命名空间域了,也就是能直接找到了。

3、模拟实现queue容器适配器

queue.h:

namespace JRH
{
	// 容器适配器
	template<class T, class Container = deque<T>>
	class queue
	{
	public:
		// 插入 尾插
		void push(const T& x)
		{
			_con.push_back(x);
		}
		// 删除 头删
		void pop()
		{
			// vector没有头删 只能用这种方法
			// 库中不能用vector
			_con.erase(_con.begin());
			//_con.front();
		}
		// 取队头元素
		T& front()
		{
			return _con.front();
		}
		// 取队尾元素
		T& back()
		{
			return _con.back();
		}
		// 输出个数
		size_t size()
		{
			return _con.size();
		}
		// 判空
		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;
	};

	void test_queue()
	{
		queue<int, list<int>> q;
		q.push(1);
		q.push(2);
		q.push(3);
		q.push(4);
		while (!q.empty())
		{
			cout << q.front() << " ";
			q.pop();
		}
		cout << endl;
	}
}

test.cpp:

#include<iostream>
#include<vector>
#include<list>
#include<queue>
#include<stack>
using namespace std;

#include"stack.h"
#include"queue.h"

int main()
{
	//JRH::test_stack1();
	JRH::test_queue();
	return 0;
}

4、介绍deque(外强中干)

(1)deque的原理介绍

**deque(双端队列):**是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。

deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组。

(2)了解一下vector和list的优势和缺陷

在这里插入图片描述

(3)中控数组概念

在这里插入图片描述
我们假设每一个指针数组指向的空间的数组的大小数量是一样的。

i、与vector比较

优势是极大缓解了扩容问题和头插头删的问题。

劣势是[]括号下标访问不够极致不够好,计算在哪个buff,在哪个buff的第几个很难,如果是高频访问[]不够好,速度慢。

计算公式:
在这里插入图片描述

ii、与list比较

优势是可以支持下标随机访问以及cpu高速缓存效率不错。

劣势是如果在中间插入数据的话怎么办?如果我们选择挪动数据,那么操作量也太大了,如果我们选择扩容,那么计算在哪个buff就变得很难了。

(4)简单介绍deque的底层

双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落在了deque的迭代器身上,因此deque的迭代器设计就比较复杂,如下图所示:
在这里插入图片描述
连续节奏:
在这里插入图片描述

(5)deque缺陷

deque有一个致命缺陷:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构时,大多数情况下优先考虑vector和list,deque的应用并不多,而目前能看到的一个应用就是,STL用其作为stack和queue的底层数据结构

(6)为什么选择deque作为stack和queue的底层默认容器

stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()和pop_back()操作的线性结构,都可以作为stack的底层容器,比如vector和list都可以;queue是先进先出的特殊线性数据结构,只要具有push_back和pop_front操作的线性结构,都可以作为queue的底层容器,比如list。但是STL中对stack和queue默认选择deque作为其底层容器,主要是因为:

  1. stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。
  2. 在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据);queue中的元素增长时,deque不仅效率高,而且内存使用率高。结合了deque的优点,而完美的避开了其缺陷。

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

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

相关文章

【C#】并行编程实战:异步流

本来这章该讲的是 ASP .NET Core 中的 IIS 和 Kestrel &#xff0c;但是我看了下这个是给服务器用的。而我只是个 Unity 客户端程序&#xff0c;对于服务器的了解趋近于零。 鉴于我对服务器知识和需求的匮乏&#xff0c;这里就不讲原书&#xff08;大部分&#xff09;内容了。本…

基于RPA的自动化流程治理方案探索及应用实践

编者荐语&#xff1a; 随着企业数字化转型进程加快&#xff0c;信息系统大量上线&#xff0c;但流程运营管理问题逐渐显现出来。为提升企业流程运营能力&#xff0c;亚信科技联合某省运营商推出智能化流程治理运营模式&#xff0c;尝试基于RPA&#xff08;机器人流程自动化&am…

IRIS搭建docker

之前把web实现了docker&#xff0c;开发或测试环境可能需要开发自己搭数据库&#xff0c;为了方便使用&#xff0c;把数据库也做一个docker。 由于原生的CentOS我还有改yum仓库&#xff0c;所以这次从之前lis搞的改好yum的镜像开始&#xff08;从改好yum的lisnew的镜像创建lis…

SaaS到底是什么,如何做?这份笔记讲明白了

阅读本篇文章&#xff0c;您将可以了解&#xff1a;1、什么是SaaS&#xff1b;2、SaaS的商业模式&#xff1b;3、SaaS的技术架构&#xff1b;4、国内比较好的SaaS平台。 一、什么是SaaS SaaS即软件即服务&#xff08;Software as a Service&#xff09;&#xff0c;是一种通过…

【数据结构】AVL树/红黑树

目录 1.AVL树&#xff08;高度平衡二叉搜索树&#xff09; 10.1.基本概念 10.2.实现 10.2.1.AVL树节点的定义 10.2.2.AVL树的插入 10.2.3.AVL树的旋转 1.新节点插入较高左子树的左侧---左左&#xff1a;右单旋 2.新节点插入较高右子树的右侧---右右&#xff1a;左单旋 3.新节点…

Python Flask构建微信小程序订餐系统 (十二)

🔥 创建切换商品分类状态的JS文件 🔥 ; var food_act_ops={init:function(){this.eventBind();},eventBind:function(){//表示作用域var that = this;$(".wrap_search select[name=status]").change(function(){$(".wrap_search").submit();});$(&qu…

对ai绘画二次元生成器你有多少了解?

在一个小镇上&#xff0c;有一位年轻的艺术家名叫艾米莉。她是个富有创意的女孩&#xff0c;总是追求着新奇和美妙的艺术体验。然而&#xff0c;她最近遇到了一些创作上的障碍&#xff0c;感觉自己的绘画已经陷入了瓶颈。在艾米莉寻找灵感的过程中&#xff0c;她听说了神秘的ai…

SQL语句(三十二)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、SQL语句类型 二、数据库操作 ​三、数据表操作 1. 数据类型 2. 查看 3. 创建 4. 删除 5. 更改 5.1 表 5.2 列 四、数据操作 4.1 增 4.2 删 4.3 改 4.4 查…

13.5.4 【Linux】常用模块简介

登陆所需要的PAM流程&#xff1a; 上面这个表格当中使用到非常多的 PAM 模块&#xff0c;每个模块的功能都不太相同&#xff0c;详细的模块情报可以在你的系统中找到&#xff1a; /etc/pam.d/*&#xff1a;每个程序个别的 PAM 配置文件&#xff1b; /lib64/security/*&#x…

网络:HCIA 1

1. 通信系统的组成&#xff1a; 终端设备&#xff1a;电脑 中间设备&#xff1a;交换机、路由器、防火墙。 传输介质&#xff1a;网线&#xff08;双绞线&#xff09;传输距离一般为100米&#xff0c;传输的是电信号。 光纤传输的是光信号。 光纤接口类型&#xff0c;方形接口…

前端(九)——探索微信小程序、Vue、React和Uniapp生命周期

&#x1f642;博主&#xff1a;小猫娃来啦 &#x1f642;文章核心&#xff1a;探索微信小程序、Vue、React和Uniapp生命周期 文章目录 微信小程序、Vue、React和Uniapp的基本定义和应用领域微信小程序生命周期生命周期概述页面生命周期应用生命周期组件和API的生命周期钩子 Vu…

看完这篇,别再说不会Spring 分库分表了

多数据源&#xff0c;读写分离&#xff0c;分库分表&#xff0c;基本上已经是现在任何一个项目的基本配置了&#xff0c;在之前的文章Spring多数据源实现https://blog.csdn.net/wangerrong/article/details/131910740 里讲了多数据源的实现&#xff0c;其实已经包含了读写分离…

广东省《5A物理抗菌纺织品》团体标准颁布

近日&#xff0c;经广东省标准化协会批准发布由广东人仁康科技有限公司主导制定的《5A物理抗菌纺织品》&#xff08;T/GDBX 073—2023&#xff09;团体标准&#xff0c;于2023年7月21日发布并实施。 根据标准制修订工作流程&#xff0c;该项标准2022年由人仁康和广检集团组织起…

【【51单片机AD/DA的分析】】

51单片机AD/DA的分析 看似单片机实验&#xff0c;其实是要学好数电 模数转换 与 数模转换 运算放大器 DA的转换就是利用运算放大器实现的 输出电压v0-(D7~D0)/256 x (VrefxRfb)/R D7~D0 就是我们控制的按键看输入多少 然后再划分256份 Vref是我们设置的一个基准电压 PWM 这种…

若依分离版——解决配置双数据源oracle,mysql分页错误问题

1. 按照若依的手册配置双数据源mysql&#xff0c;oracle 2. 在service指定 数据源 DataSource(value DataSourceType.MASTER) 或者DataSource(value DataSourceType.SLAVE) Service public class SysPostServiceImpl implements ISysPostService {/*** 查询岗位信息集合* …

分享10个NodeJS相关的专业级工具

Node.js已成为开发人员创建强大且可扩展的Web应用程序的首选选项。根据2022年StackOverflow开发者调查&#xff0c;Node.js被评为专业开发人员中使用最广泛的Web框架。这个成功可以归功于其庞大的生态系统&#xff0c;其中提供了许多工具和框架。了解并接纳这个生态系统对于优化…

前端面试题-JS进阶

1 内置类型 JS 中分为七种内置类型&#xff0c;七种内置类型⼜分为两⼤类型&#xff1a;基本类型和对象&#xff08; Object &#xff09;。基本类型有六种&#xff1a; null &#xff0c; undefined &#xff0c; boolea n&#xff0c; number &#xff0c; string &#xff…

【数据动态填充到element表格;将带有标签的数据展示为文本格式】

一&#xff1a;数据动态填充到element表格&#xff1b; 二&#xff1a;将带有标签的数据展示为文本格式&#xff1b; 1、 <el-row><el-col :span"24"><el-tabs type"border-card"><el-tab-pane label"返回值"><el-…

计算机流水线在正常程序中的体现(效果可视)

众所周知,流水线技术对于软件开发人员不是可见的(visiable),毕竟已经在在机器语言之下,是组成机器语言的基本逻辑 但今天我就带领大家看看我新发现的结果,那就是流水线的可视效果,包括流水线预测技术的侧面体现,当然也是可见的 首先我先声明一下需要的基础,需要懂16位以及32位操…

leetcode 面试题01.04 回文排列

⭐️ 题目描述 &#x1f31f; leetcode链接&#xff1a;回文排列 思路&#xff1a;回文串两种可能。只有一个字符出现1次其他字符都是偶数次。要么都是偶数次。统计字母的个数即可。 代码&#xff1a; bool canPermutePalindrome(char* s){// 回文串两种可能// 1. 只有一个字…