C++ stack and queue

news2024/9/24 5:21:59

1. stack模拟实现


C++STL中的栈是一种容器适配器,它是将vector/list进行封装,push/pop等接口直接调用vector/list的接口即可,不需要像C语言那样,从头开始造轮子

namespace byh
{
	template<class T, class Container = deque<T>>
	class stack
	{
	public:
		void push(const T& val)
		{
			_con.push_back(val);
		}

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

int main()
{
	byh::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;
}

在模板实例化时,我们给栈传什么容器,它就调用该容器的接口,默认容器是deque

deque是一种双端队列,它结合了vectorlist 的优势

vector

  • 优势:能够随机访问
  • 劣势:头插/删,中间插/删要挪动数据,效率低;扩容有消耗

list

  • 优势:任意位置插入/删除效率高
  • 劣势:不支持随机访问

可以说,vectorlist是两个互补的容器,既然这样,能不能把这两个容器的优势结合;因为有这样的需求,就有了deque

它的底层会有一个中控指针数组,每个元素都指向一个长度为N的数组

尾插时,如果当前的所有数组都满了,则开辟新的指针,指向新的数组,插入元素

头插时,在数组中,以从后往前的顺序依次插入元素

访问第i个元素时,如果第一个数组没满,i减去第一个数组元素个数,进行下面的运算:

  • i / N -->找到该元素在第几个数组
  • i % N -->找到是在该数组的第几个元素

如果第一个数组满了,直接进行上面的运算

如果中控指针数组满了,进行扩容,虽然最总还是要扩容,但消耗上大大降低

deque

  • 优点:头插/删,尾插/删效率都不错
  • 缺点:中间插/删会比较麻烦,不如list;随机访问的效率不如vector

stackqueue的默认容器使用deque的原因就在于它的头插/删,尾插/删效率可以,并且不会使用随机访问或者中间插/删

2.queue模拟实现


namespace byh
{
	template<class T, class Container = deque<T>>
	class queue
	{
	public:
		void push(const T& val)
		{
			_con.push_back(val);
		}

		void pop()
		{
			_con.pop_front();
		}

		T& back()
		{
			return _con.back();
		}

		T& front()
		{
			return _con.front();
		}

		const T& back() const
		{
			return _con.back();
		}

		const T& front() const
		{
			return _con.front();
		}

		bool empty()
		{
			return _con.empty();
		}

		size_t size()
		{
			return _con.size();
		}

	private:
		Container _con;
	};
}

int main()
{
	byh::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;
}

3. priority_queue


queue系列中,除了先进先出的普通queue之外,还有一个优先级队列priority_queue

pop时,不再是先进先出,而是按规定的优先级取出元素

#include<iostream>
#include<queue>

int main()
{
	std::priority_queue<int> pq;
	pq.push(3);
	pq.push(2);
	pq.push(4);
	pq.push(5);
	pq.push(1);
	while (!pq.empty())
	{
		std::cout << pq.top() << " ";
		pq.pop();
	}
	std::cout << std::endl;
	return 0;
}
// 输出 5 4 3 2 1

在这里插入图片描述

仿函数实际上是一个类,只不过我们可以用函数的方式去使用它

它的内部是对()运算符的重载

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

void Test()
{
    byh::Less<int> less;
    cout << less(1, 2) << endl;// 有名对象

    cout << less.operator()(1, 2) << endl;

    cout << byh::Less<int>()(1, 2) << endl;// 匿名对象
}

我们可以在仿函数内部控制比较的逻辑,生活中大部分场景下都是用自定义类型描述一个对象,如何控制该对象的比较,进行排序,就需要我们规定好比较方式

struct Goods
{
	Goods(const char* str, double price, int evaluate)
		:_name(str)
		,_price(price)
		,_evaluate(evaluate)
	{}

	string _name;
	double _price;
	int _evaluate;
};

struct ComparePriceLess
{
	bool operator()(const Goods& x, const Goods& y)
	{
		return x._price < y._price;
	}
};

//...

int main()
{
	vector<Goods> v = { {"苹果",3.1,2},{"草莓",4.2,4},{"苹果",2.6,3} };
	sort(v.begin(), v.end(), ComparePriceLess());
	return 0;
}

3.1 模拟实现

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

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

	template<class T, class Container = vector<T>, class Compare = Less<T>>
	class priority_queue
	{
	public:
		void AdjustUp(int child)
		{
			int parent = (child - 1) / 2;
			Compare com;

			while (child > 0)
			{
				if (com(_con[parent], _con[child]))
				{
					swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else break;
			}
		}

		void push(const T& val)
		{
			_con.push_back(val);
			AdjustUp(size() - 1);
		}

		void AdjustDown(int parent)
		{
			int child = parent * 2 + 1;
			Compare com;

			while (child < size())
			{
				if (child + 1 < size() && com(_con[child], _con[child + 1]))
					child++;
				if (com(_con[parent], _con[child]))
				{
					swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else break;
			}
		}

		void pop()
		{
			swap(_con[0], _con[size() - 1]);
			_con.pop_back();
			AdjustDown(0);
		}

		T& top()
		{
			return _con[0];
		}

		const T& top() const
		{
			return _con[0];
		}

		size_t size() const
		{
			return _con.size();
		}

		bool empty() const
		{
			return _con.empty();
		}

	private:
		Container _con;
	};

4. Reverse_Iterator


反向迭代器与正向迭代器功能类似,它们都是遍历,不同的是,反向迭代器++往前走,--往后走

我们可以对正向迭代器的++--修改,但这样做,每个容器的迭代器都要进行拷贝修改,不仅代码冗余,还麻烦

于是,我们用const迭代器的思路,将Reverse_Iterator写成一个模板,我们给它传哪个容器的迭代器,编译器就帮我们形成哪个容器的反向迭代器,从而减少我们的工作量

STL中,rbegin()rend()的位置与begin()end()相反

访问时,是解引用当前位置的上一个位置

在这里插入图片描述

namespace byh
{
	template<class Iterator, class Ref, class Ptr>
	struct ReverseIterator
	{
		Iterator _it;

		ReverseIterator(Iterator it)
			:_it(it)
		{}

		Ref operator*()
		{
			Iterator temp = _it;
			return *(--temp);
		}

		Ptr operator->()
		{
			return &(operator*());
		}

		// ++it
		ReverseIterator operator++()
		{
			_it--;
			return *this;
		}

		// --it
		ReverseIterator operator--()
		{
			_it++;
			return *this;
		}

		bool operator!=(ReverseIterator rit)
		{
			return _it != rit._it;
		}
	};
}
erator it)
			:_it(it)
		{}

		Ref operator*()
		{
			Iterator temp = _it;
			return *(--temp);
		}

		Ptr operator->()
		{
			return &(operator*());
		}

		// ++it
		ReverseIterator operator++()
		{
			_it--;
			return *this;
		}

		// --it
		ReverseIterator operator--()
		{
			_it++;
			return *this;
		}

		bool operator!=(ReverseIterator rit)
		{
			return _it != rit._it;
		}
	};
}

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

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

相关文章

python实验二 函数与类的应用

实验二 实验题目 1、请编写一个函数SDSearch(txt, word)&#xff0c;其中&#xff0c;txt是一段文本&#xff0c;word是给定的词汇&#xff0c;函数SDSearch可以找到word在txt中的所有位置&#xff0c;并将它们做为返回值返回&#xff0c;编写函数main()调用SDSearch(txt, wo…

连锁收银系统批量调整商品价格教程

1、进入系统后台&#xff0c;系统后台登录网址&#xff1a; 2、点击商品>商品调价 3、将按模板整理好的商品价格数据导入即可。 Tips&#xff1a;每次导入的商品数量不要超过6000 条。

英语翻译中文,如何找专业的翻译公司?

在国际交流日益频繁的今天&#xff0c;翻译业务如雨后春笋般崭露头角&#xff0c;众多翻译公司如百花争艳般崭露头角。然而&#xff0c;国内翻译公司水平层参不齐。为了确保翻译的质量和准确性&#xff0c;选择一家专业的翻译公司至关重要。那么&#xff0c;英语翻译中文&#…

Case中default的综合结果

在使用case语句时&#xff0c;不完备的case语句会导致Vivado综合时推断出锁存器。下面通过实例来详细看看各种情况下的综合结果&#xff1a; 1.完备的case语句 下述的verilog对应的电路结构是一个8选一的多路复用器&#xff1a; module case_test(input [2:0]sel,input data…

学习如何使用PyQt5实现notebook功能

百度搜索“pyqt5中notebook控件”&#xff0c;AI自动生成相应例子的代码。在 PyQt5 中&#xff0c;QTabWidget 类被用作 Notebook 控件。以下是一个简单的示例&#xff0c;展示如何创建一个带有两个标签的 Notebook 控件&#xff0c;并在每个标签中放置一些文本。 import sys f…

咖啡机定量出水的原理是什么

咖啡机实现定量出水的原理主要依赖于流量计的使用。流量计是一种能够测量液体或气体通过管道的速度和体积的装置。在咖啡机中&#xff0c;常用的小型流量计有霍尔式流量计和光电式流量计两种。 霍尔式流量计利用了霍尔效应的原理来实现流量测量。它包含一个带有两极磁铁的叶轮…

为什么不能在cPanel收到电子邮件?

本周有一个客户&#xff0c;购买Hostease的虚拟主机&#xff0c;询问我们的在线客服&#xff0c;为什么不能在cPanel收到电子邮件?我们为用户提供教程&#xff0c;用户很快解决了遇到的问题。在此&#xff0c;我们分享这个操作教程&#xff0c;希望可以对您有帮助。 如果您遇到…

Nodejs内存管[Mark-Sweep算法][Mark-Compact]

内存控制 Mark-Sweep & Mark-Compact 对于老生代的对象&#xff0c;存活对象占较大的比重&#xff0c;采用scvenge方法会存在如下问题 1. 存活对象较多&#xff0c;复制存活对象的效率很低 2. 浪费一半空间的问题因此v8在老生代中主要采用了Mark-Sweep和Mark-Compact相结…

西门子数控网络IP设定配置

总结&#xff1a;menuselect-诊断-屏幕下方右翻页找到tcp/ip&#xff0c;进去选择tcp/ip诊断&#xff0c;进去选择x130网口&#xff0c;点击更改&#xff0c; 如果没有更改&#xff0c;menuselect-调试-口令&#xff0c;输入口令 sunrise 然后重新配置tcp/ip&#xff0c;配置完…

Unity3D DOTween

简单介绍一下 DOTween 插件的使用。 导入插件 先到 Asset Store 获取 DOTween 插件&#xff0c;然后在 Package Manager 的 My Assets 中搜索&#xff0c;下载并导入插件。 导入后&#xff0c;会自动弹出一个窗口&#xff0c;提示需要先对插件进行配置。 点击上图中的按钮&am…

navicat premium16.3.9重置

软件下载 官网地址&#xff1a;https://navicat.com.cn/products/ # 准备脚本 1、建一个txt 2、复制以下代码 3、修改文件格式为bat 4、运行bat文件 5、重新打开navicat&#xff0c;试用期重置为14 经测试16.2.3以上版本均可用 echo off set dnInfo set dn2ShellFolder set r…

迅饶科技 X2Modbus 网关 AddUser 任意用户添加漏洞复现

0x01 产品简介 X2Modbus是上海迅饶自动化科技有限公司Q开发的一款功能很强大的协议转换网关, 这里的X代表各家不同的通信协议, 2是T0的谐音表示转换, Modbus就是最终支持的标准协议是Modbus协议。用户可以根据现场设备的通信协议进行配置,转成标准的Modbus协议。在PC端仿真…

从零开始学AI绘画,万字Stable Diffusion终极教程(六)

【第6期】知识补充 欢迎来到SD的终极教程&#xff0c;这是我们的第六节课&#xff0c;也是最后一节课 这套课程分为六节课&#xff0c;会系统性的介绍sd的全部功能&#xff0c;让你打下坚实牢靠的基础 1.SD入门 2.关键词 3.Lora模型 4.图生图 5.controlnet 6.知识补充 …

三维变换矩阵实战——三维点云的旋转、缩放、镜像、错切、平移、正交投影

一、旋转矩阵&#xff08;右手坐标系&#xff09; 绕x轴旋转 旋转矩阵&#xff1a;右边矩阵是点云的原始坐标&#xff0c;左边的是旋转矩阵 可视化&#xff1a;绕x轴旋转90度 代码&#xff1a; import vtk import numpy as np import mathdef pointPolydataCreate(pointClou…

毕业设计:《基于 Prometheus 和 ELK 的基础平台监控系统设计与实现》

前言 《基于 Prometheus 和 ELK 的基础平台监控系统设计与实现》&#xff0c;这是我在本科阶段的毕业设计&#xff0c;通过引入 Prometheus 和 ELK 架构实现企业对指标与日志的全方位监控。并且基于云原生&#xff0c;使用容器化持续集成部署的开发方式&#xff0c;通过 Sprin…

Eayswoole 报错 crontab info is abnormal

在执行一个指定的定时任务时 如 php easyswoole crontab show 报错 crontab info is abnormal 如下图所示&#xff1a; 查询了半天 修改了如下配置&#xff1a; 旧的 // 创建定时任务实例 $crontab new \EasySwoole\Crontab\Crontab($crontabConfig); 修改后&#…

PHP源码_众筹商城

众筹商城源码 众筹商品平台 商城加共识元富之路 网上商城众筹 前端是编译后的&#xff0c;后端PHP&#xff0c;带商城 运行截图 源码贡献 https://githubs.xyz/boot?app39 部分数据库表 CREATE TABLE ti_shopro_store (id int(11) NOT NULL AUTO_INCREMENT COMMENT ID,nam…

微信小程序生成二维码加密(CryptoJS4.0加密PHP8.0解密)AES方式加密

1、小程序创建 crypto-js.js和crypto.js两个文件&#xff08;点击文件即可&#xff09; 2、小程序js页面引入 var crypto require(../../utils/crypto.js);//注意路径是否正确3、使用 let data {id: that.data.id,name: dx}console.log(JSON.stringify(data))console.log(&…

信创国产化的基础知识

信创&国产化的基础知识 核心技术是国之重器&#xff0c;核心技术受制于人是我们最大的隐患。 实践反复告诉我们&#xff0c;关键核心技术是要不来、买不来、讨不来的。 要打好科技仪器设备、操作系统和基础软件国产化攻坚战&#xff0c;鼓励科研机构、高校同企业开展联合攻…

深度学习之GAN网络

目录 关于GAN网络 关于生成模型和判别模型 GAN网路的特性和搭建步骤&#xff08;以手写字体识别数据集为例&#xff09; 搭建步骤 特性 GAN的目标函数&#xff08;损失函数&#xff09; 目标函数原理 torch.nn.BCELoss&#xff08;实际应用的损失函数&#xff09; 代码…