C++ stack和queue模拟实现

news2024/11/16 20:40:56

目录

    • stack
    • 习题练习
      • 逆波兰表达式求值
      • 基本计算器
    • stack模拟实现
    • queue
    • queue模拟实现
    • deque了解
    • priority_queue
    • priority_queue模拟实现
    • 仿函数

stack

在这里插入图片描述
stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。

stack的使用(最常用的):
在这里插入图片描述

习题练习

逆波兰表达式求值

在这里插入图片描述
思路:
遇到操作数就入栈
遇到操作符就取栈顶的两个操作数运算,结果再入栈

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();
    }
};

基本计算器

思路:
在这里插入图片描述

class Solution {
public:
    int pre(char ch)//优先级判断
    {
        if(ch=='+'
        || ch=='-')
        return 1;
        else if(ch=='(' || ch==')')
        return 3;
        else//如果有*/
        return 2;
    }
    int calculate(string s) {
        vector<int> v;
        stack<char> st;
        int i=0;
        for(int i=0;i<s.size();i++)
        {
            if(isdigit(s[i]))//遇到操作数放到vector里
            {
                string s1;
                while(isdigit(s[i]))
                {
                    s1+=s[i++];
                }
                i--;
                v.push_back(stoi(s1));

                //如果遇到是-1
                if(v.size()==st.size()==1)
                {
                    v.pop_back();
                    st.pop();
                    v.push_back(-stoi(s1));
                }
            }

            else if(s[i]!=' ')//遇到操作符
            {
                if(s[i]=='(')
                {
                    //递归解决
                    string tmp(s,i+1);
                    v.push_back(calculate(tmp));

                    //找到)
                    i++;
                    int count=1;//代表1个(,对应着一个),如果在找的过程中发现了第二个(,count++
                    while(count!=0)
                    {
                        if(s[i]=='(')
                        {
                            count++;
                        }
                        else if(s[i]==')')
                        {
                            count--;
                        }
                        if(count!=0)
                        i++;
                    }

                    //递归解决完之后,面临和上面遇到-1一样的情况
                    if(v.size()==st.size()==1)
                    {
                        int a=v.back();
                        v.pop_back();
                        st.pop();
                        v.push_back(-a);
                    }
                    continue;
                }
                if(s[i]==')')
                {
                    break;
                }

                while(!st.empty())
                {
                    char top=st.top();
                    //ch运算符优先级比top高,入栈
                    if(pre(s[i])>pre(top))
                    {
                        st.push(s[i]);
                    }
                    else
                    {
                        _operator(st,v);
                    }
                }
                if(st.empty())
                {
                    st.push(s[i]);
                }
            }
        }

        while(!st.empty())
        {
            _operator(st,v);
        }

        return v.back();
    }
    void _operator(stack<char>& st,vector<int>& v)//出栈顶操作符对两个操作数运算然后将结果放回vector
    {
        char top=st.top();
        //出栈顶元素
        st.pop();
        int right=v.back();
        v.pop_back();
        int left=v.back();
        v.pop_back();
        //运算v中数据把结果放回去
        switch(top)
        {
            case'+':
                v.push_back(left+right);
                break;
            case'-':
                v.push_back(left-right);
                break;
        }
    }
    
};

stack模拟实现

namespace st
{
	template<class T,class Container = deque<T>>
	//不管Container这个底层容器是谁,都可以适配栈
	class stack
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_back();
		}
		const T& top()
		{
			return _con.back();
		}
		bool empty()
		{
			return _con.empty();
		}
		size_t size()
		{
			return _con.size();
		}
	private:
		Container _con;
	};
};

void test_stack()
{
    st::stack<int, vector<int>> v;
    v.push(1);
    v.push(3);
    v.push(2);
    v.push(7);
    v.push(5);

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

int main()
{
    test_stack();
    return 0;
}

queue

在这里插入图片描述

队列是一种容器适配器,先进先出,其中从容器一端插入元素,另一端提取元素。

queue模拟实现

queue的接口中存在头删和尾插,因此使用vector来封装效率太低,可以借助list来模拟实现queue

namespace q
{
	template<class T, class Container=deque<T>>
	class queue
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_front();
		}
		const T& front()
		{
			return _con.front();
		}
		const T& back()
		{
			return _con.back();
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
};

void test_queue()
{
    q::queue<int, list<int>> q;
    q.push(4);
    q.push(3);
    q.push(2);
    q.push(9);
    q.push(5);

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

int main()
{
    test_queue();

    return 0;
}

deque了解

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

deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()和pop_back()操作的线性结构,都可以作为stack的底层容器,比如vector和list都可以;queue是先进先出的特殊线性数据结构,只要具有push_back和pop_front操作的线性结构,都可以作为queue的底层容器,比如list。

选deque是因为:

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

priority_queue

在这里插入图片描述
优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成
堆的结构,因此priority_queue就是堆

默认的Compare是less,也就是大堆
想创建的是小堆,可以用greater

priority_queue<int,vector<int>,greater<int>> q

使用sort和priority_queue时参数是不同的
在这里插入图片描述

priority_queue模拟实现

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

template<class T>
class Less
{
public:
	bool operator()(const T& x, const T& y)
	{
		return x < y;
	}
};

template<class T>
class Greater
{
public:
	bool operator()(const T& x, const T& y)
	{
		return x > y;
	}
};

namespace my_pq
{
	template<class T,class Comtainer = vector<T>,class Compare = Less<T>>
	class priority_queue
	{
	public:
		priority_queue(){}

		//根据迭代器区间初始化
		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
			:_con(first, last)
		{
			//向下调整
			size_t n = _con.size();
			for (size_t i = (n - 2) / 2; i >= 0; i--)
			{
				adjust_down(i);
			}
		}
		void adjust_up(int child)
		{
			Compare com;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				//if (_con[parent] < _con[child])
				if (com(_con[parent],_con[child]))
				{
					swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
		void adjust_down(int parent)
		{
			Compare com;
			int child = parent * 2 + 1;
			size_t n = _con.size();
			while (child < n)
			{
				//if (child + 1 < n
				//	&& _con[child] < _con[child + 1])
				if (child + 1 < n
					&& com(_con[child], _con[child + 1]))
				{
					++child;
				}

				//if (_con[parent] < _con[child])
				if (com(_con[parent], _con[child]))
				{
					swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
		void push(const T& x)
		{
			_con.push_back(x);
			adjust_up(_con.size() - 1);//向上调整,传child
		}
		void pop()
		{
			swap(_con[0],_con[_con.size()-1]);//交换堆顶到末尾再删除
			_con.pop_back();
			adjust_down(0);//向下调整,传parent
		}
		const T& top()
		{
			return _con[0];
		}
		bool empty()
		{
			return _con.empty();
		}
	private:
		Comtainer _con;
	};
}
int main()
{
	//my_pq::priority_queue<int> q;
	my_pq::priority_queue<int,vector<int>,Greater<int>> q;
	q.push(2);
	q.push(1);
	q.push(5);
	q.push(3);
	while (!q.empty())
	{
		cout << q.top() << " ";
		q.pop();
	}
	return 0;
}

仿函数

在模拟实现优先级队列的时候,priority_queue是大堆还是小堆取决于比较方法,可以用函数指针,但函数指针可读性不是很好,为了替代函数指针,仿函数就是个好方法
在这里插入图片描述

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

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

相关文章

阶段六-Day02-Maven

一、学习Maven 使用Maven创建Web项目&#xff0c;并部署到服务器。 二、Maven介绍及加载原理 1. 介绍 Maven是使用Java语言编写的基于项目对象模型&#xff08;POM&#xff09;的项目管理工具。开发者可以通过一小段描述信息来管理项目的构建、报告和文档。 使用Maven可以…

Supervised Contrastive Pre-training for Mammographic Triage Screening Model

方法 品红色箭头表示将生成的孪生编码器分别迁移到单视角学习模块和双视角学习模块

C语言--文件操作详解(2)(文本文件和二进制文件,文件读取结束的判定,用函数进行文件的拷贝,文件缓冲区)

前言 本篇文章主要介绍了文本文件和二进制文件&#xff0c;文件读取结束的判定&#xff0c;如何使用函数进行文件的拷贝&#xff0c;文件缓冲区的相关知识。 以及具有保存功能的八功能通讯录的源码。 文章目录 前言1.文本文件和二进制文件2.文件读取结束的判定2.1 被错误使用…

Modality-invariant Visual Odometry for Embodied Vision 代码复现

代码地址 https://github.com/memmelma/VO-Transformer/tree/dev 环境配置 1.拉取github库 git clone https://github.com/memmelma/VO-Transformer.git cd VO-Transformer/2.创建环境 创建environment.yml name: vot_nav channels:- pytorch- conda-forge dependencies:-…

gpio内部结构(一)

一&#xff0c;GPIO内部结构 1&#xff0c;保护二极管 * 引脚内部加上这两个保护二级管可以防止引脚外部过高或过低的电压输入。 * 当引脚电压高于 VDD_FT 或 VDD 时&#xff0c;上方的二极管导通吸收这个高电压。 * 当引脚电压低于 VSS 时&#xff0c;下方的二极管导通&…

Linux 文件链接

Linux 下的文件链接有两类。一个是类似于 win 电脑的快捷方式&#xff0c;我们称为软链接&#xff0c;软链接也可以叫做符号链接。另一种是通过文件系统的 inode 连接来产生的&#xff0c;类似于 windows 电脑的复制&#xff0c;但是不产生新的文件&#xff0c;我们称为硬链接。…

2023.10.10

运算符重载 类外函数实现&#xff1a; #include <iostream>using namespace std;class Good {//算数friend const Good operator*(const Good &L,const Good &R);friend const Good operator(const Good &L,const Good &R);friend const Good operator…

【网络豆送书第五期】Kali Linux高级渗透测试

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 公众号&#xff1a;网络豆云计算学堂 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a; 网络豆的主页​​​​​ 本期好书推荐&#xff1a;《Kali Linux高级渗透测试…

在Openresty中使用lua语言向请求浏览器返回请求头User-Agent里边的值

可以参考《Linux学习之Ubuntu 20.04在https://openresty.org下载源码安装Openresty 1.19.3.1&#xff0c;使用systemd管理OpenResty服务》安装Openresty。 然后把下边的内容写入到openresty配置文件/usr/local/openresty/nginx/conf/nginx.conf&#xff08;根据实际情况进行选…

vue使用localstorage超出限制解决方法

最近在项目中&#xff0c;遇到一个报错&#xff0c;QuotaExceededError: The quota has been exceeded。如图&#xff1a; 搜索了一下&#xff0c;结合项目代码&#xff0c;得到的结论是localStorage超出5M限制了&#xff0c;项目中使用了vuex-persistedstate插件&#xff0c;…

机器学习、深度学习相关的项目集合【自行选择即可】

【基于YOLOv5的瓷砖瑕疵检测系统】 YOLOv5是一种目标检测算法&#xff0c;它是YOLO&#xff08;You Only Look Once&#xff09;系列模型的进化版本。YOLOv5是由Ultralytics开发的&#xff0c;基于一阶段目标检测的概念。其目标是在保持高准确率的同时提高目标检测的速度和效率…

win11安装IIS步骤-已验证23.10.10

IIS服务使用 步骤一&#xff1a;打开控制面板 通过 控制面板— 程序— 启用或关闭Windows功能 — 选择Internet Information Services默认安装IIS&#xff0c;如下图步骤所示 步骤二&#xff1a;打开IIS服务 建议根据下图勾选&#xff0c;建议全选安装&#xff0c;以便后续发…

计算机算法分析与设计(9)---0-1背包问题(含C++代码)

文章目录 一、概述1.1 问题描述1.2 算法思想 二、代码2.1 题目描述2.2 代码编写 一、概述 1.1 问题描述 1. 0-1背包问题&#xff1a;给定 n n n 种物品和一背包。物品 i i i 的体积是 v i v_i vi​&#xff0c;其价值为 w i w_i wi​&#xff0c;背包的容量为 c c c。问应…

winform窗体控件太多显示不过来,怎么实现滚动条

winform窗体控件太多显示不过来&#xff0c;怎么实现滚动条 Winform Panel实现滚动条 一、创建panel 在界面上拖拽一个父级Panel1&#xff0c;然后在Panel1里面拖拽一个子级Panel2 设置父级Panel1的AutoScroll属性为True 属性设置好后&#xff0c;当子级高度或者宽度大于父…

promtail multiline 堆栈日志处理

找到自己的promtail.yaml中job_name段落&#xff0c;增加multiline段落&#xff0c;下面文件只是部分内容&#xff0c;只需要修改firstline后面的正则表达式匹配日志行首&#xff0c;如果堆栈换行后不是此格式行首&#xff0c;将自动把堆栈的行合并到上一行中。 - job_name: k…

【管理运筹学】第 9 章 | 网络计划(2,时间参数的计算 —— 工作时间的确定与事项的时间参数)

文章目录 引言一、工作时间的确定二、事项的时间参数2.1 事项的最早开始时间2.2 事项的最迟结束时间2.3 事项的时差2.4 利用事项的时间参数来确定关键线路 引言 计算网络图中有关的时间参数&#xff0c;主要目的是找到关键线路&#xff0c;为网络计划的优化、调增和执行提供明…

LabVIEW玩转魔方

LabVIEW玩转魔方 使用LabVIEW创建一个3D魔方&#xff0c;并找出解谜题的秘密&#xff0c;给朋友留下深刻深刻的印象。游戏中内置的机制使每张脸都能独立转动&#xff0c;从而混合颜色。要解决难题&#xff0c;每个面必须是相同的纯色 魔方的奥秘在于它的简单性和不可解性。这是…

点餐小程序实战教程08-购物车功能开发

目录 1 创建购物车2 增加数量3 减少数量4 切换分类时回填数据5 显示购物车信息总结 我们上一篇搭建了点餐业务的数据初始化加载&#xff0c;本篇实现一下加入购物车的功能。在购物车设计的时候有两种方案&#xff0c;一种是使用数据表的方案&#xff0c;一种是使用变量的方案。…

手机拍摄的视频噪点很多怎么办,视频怎么做降噪处理?

现如今&#xff0c;智能手机已经成为了我们生活中必不可少的存在。而随着智能手机越来越强大&#xff0c;很多人已经开始使用手机来拍摄各种类型的视频。但是由于手机的限制&#xff0c;很多人会发现自己拍摄的视频存在着很多的噪点。那么&#xff0c;我们该怎样来解决拍摄视频…

深入理解强化学习——强化学习和有监督学习

分类目录&#xff1a;《深入理解强化学习》总目录 通过前文的介绍&#xff0c;我们现在应该已经对强化学习的基本数学概念有了一定的了解。这里我们回过头来再看看一般的有监督学习和强化学习的区别。以图片分类为例&#xff0c;有监督学习&#xff08;Supervised Learning&…