C++初阶 —— stack/queue

2023-05-16

目录

一,容器适配器

deque双端队列

二,stack栈

stack接口

stack模拟实现

三,queue队列

queue接口

queue模拟实现

四,priority_queue优先级队列

priority_queue接口

priority_queue模拟实现

注:Date*,无法转化为const Date* &;


一,容器适配器

  • 适配器是一种设计模式,该模式是将一个类的接口转换成用户希望的另一个接口;
  • 虽然stack、queue中可以存元素,但在STL中并没有划为容器行列,而是将其称为容器适配器;这是因为他们只是对其他的接口进行了包装,STL中stack、queue默认的底层容器为deque;

deque双端队列

  • 是一种双开口的“连续”空间的数据结构;
  • 双开口,即头尾两端都可高效插入和删除操作,时间复杂度为O(1);
  • “连续”空间,其实并非真正的连续空间,而是由一段段连续的小空间拼接而成,类似于一个动态的二维数组;
  • 与vector比较,头插效率高,无需挪动数据;vector的cpu高速缓存命中率高,但增容代价大且存在空间浪费;
  • 与list比较,空间利用率较高;list按需申请或释放空间,任意插入删除效率高,不支持随机访问,cpu高速缓存命中率低;

优缺点

  • 非常适合头插/尾插,头删/尾删,默认适合做stack/queue适配器;
  • 中间插入/删除数据非常麻烦,效率不高;
  • 不适合遍历,遍历时迭代器要频繁的检测是否到达边界;
  • deque可以说是一种折中的方案,随机访问不及vector,任意位置插入删除不及list;

 注:

  • stack是一种LIFO的特殊线性数据结构,只要满足尾插尾删操作均可作为其底层容器,如vector、list;
  • queue是一种FIFO的特性线性数据结构,只要满足尾插头删操作均可作为底层容器,如list;
  • stack、queue默认选择deque作为其底层容器,是因为stack、queue没有迭代器无需遍历,只要在一端或两端操作即可,stack增容时deque比vector效率高不需要大量挪动数据,queue元素增长时,不仅效率高,且内存使用率也高;
int main()
{
	deque<int> dq;
	dq.push_back(1);
	dq.push_back(2);
	dq.push_front(3);
	dq.push_front(4);
	cout << dq[0] << endl;
	cout << dq.front() << endl;
	cout << dq.back()<< endl;
	dq.pop_back();
	dq.pop_front();

	deque<int>::iterator it = dq.begin();
	while (it != dq.end())
	{
		cout << *it << " ";
		++it;
	}
	return 0;
}

二,stack栈

  • stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,只能从容器的一端进行元素的插入与提取操作;
  • stack是作为容器的适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层,元素在特定容器尾部即栈顶被压入和弹出;
  • 底层容器可以是任何标准的容器类模板或其他特定的容器类,这些容器类应支持,empty、back、push_back、pop_back操作;
  • 标准容器vector、deque、list均符号要求,如stack未指定特定的底层容器,默认使用deque;

stack接口

  • stack(),构造空栈;
  • empty(),判断释放为空栈;
  • size(),返回元素个数;
  • top(),返回栈顶元素个数;
  • push(),压入元素;
  • pop(),弹出元素;
int main()
{
	stack<int> st;
	st.push(1);
	st.push(2);
	st.top();
	st.pop();
	st.size();
	st.empty();
	return 0;
}

stack模拟实现

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();
	}
	size_t size()
	{
		return _con.size();
	}
	bool empty()
	{
		return _con.empty();
	}
private:
	container _con;
};

int main()
{
	stack<int, list<int>> st;
	st.push(1);
	st.push(2);
	st.push(3);
	st.push(4);
	while (!st.empty())
	{
		cout << st.top() << " ";
		st.pop();
	}
	return 0;
}

三,queue队列

  • queue是一种容器适配器,专门用于在先进先出中操作,其中从容器一端插入元素,另一端提取元素;
  • 队列作为容器适配器实现,容器适配器即将特定容器封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素,元素从队尾入队列,从对头出队列;
  • 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类,该底层容器应至少支持,empty、size、front、back、push_back、pop_front操作;
  • 标准容器类deque和list默认要求,如queue没有实例化指定容器类,默认使用deque;

queue接口

  • queue(),构造空队列;
  • empty(),判断释放为空栈;
  • size(),返回有效元素个数;
  • front(),返回对头元素引用;
  • back(),返回队尾元素引用;
  • push(),在队尾将元素入队列;
  • pop(),将对头元素出队列;
int main()
{
	queue<int> q;
	q.push(1);
	q.push(2);
	q.front();
	q.back();
	q.pop();
	q.size();
	q.empty();
	return 0;
}

queue模拟实现

template <class T, class container = deque<T>>
class queue
{
public:
	void push(const T& val)
	{
		_con.push_back(val);
	}
	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;
};

int main()
{
	queue<int, list<int>> st;
	st.push(1);
	st.push(2);
	st.push(3);
	st.push(4);
	while (!st.empty())
	{
		cout << st.front() << " ";
		st.pop();
	}
	return 0;
}

四,priority_queue优先级队列

  • 优先级队列,默认使用vector作为底层容器;
  • vector上使用堆算法,将元素构造成堆结构;
  • 优先级队列其实是堆,默认为大堆;

priority_queue接口

  • priority_queue(),构造空优先级队列;
  • priority_queue(InputIterator first,InputIterator last),用指定范围构造优先级队列;
  • push,插入元素;
  • pop,删除堆顶元素;
  • top,返回堆顶元素;
  • size,返回有效元素个数;
  • empty,检测是否为空;
int main()
{
	vector<int> v = { 1,2,3,4 };
	priority_queue<int> pq(v.begin(), v.end());
	pq.push(3);
	pq.push(5);
	while (!pq.empty())
	{
		cout << pq.top() << " ";
		pq.pop();
	}
	return 0;
}

priority_queue模拟实现

template<class T, class container = vector<T>, class compare = less<T>>
class priority_queue
{
public:
	priority_queue()
	{}

	template<class InputIterator>
	priority_queue(InputIterator first, InputIterator last)
	{
		while (first != last)
		{
			push(*first);
			++first;
		}
	}

	void push(const T& val)
	{
		_con.push_back(val);
		AdjustUp(_con.size() - 1);
	}
	void pop()
	{
		std::swap(_con[0], _con[_con.size() - 1]);
		_con.pop_back();
		AdjustDown(0);
	}
	const T& top()const
	{
		return _con.front();
	}
	size_t size()const
	{
		return _con.size();
	}
	bool empty()const
	{
		return _con.empty();
	}

	void AdjustDown(size_t parent)
	{
		size_t child = parent * 2 + 1;
		while (child < _con.size())
		{
			if (child + 1 < _con.size() && compare()(_con[child], _con[child + 1]))
				child++;
			if (compare()(_con[parent], _con[child]))
			{
				std::swap(_con[parent], _con[child]);
				parent = child;
				child = parent * 2 + 1;
			}
			else
				break;
		}
	}
	void AdjustUp(size_t child)
	{
		size_t parent = (child - 1) / 2;
		while (child > 0)
		{
			if (compare()(_con[parent], _con[child]))
			{
				std::swap(_con[parent], _con[child]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
				break;
		}
	}

private:
	container _con;
};

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

注,嵌套依赖名字需添加关键字typename

template<class container>
void print(const container& con) 
{
	//无法确定container::iterator是类型,还是静态成员变量
	//需在前添加typename
	typename container::const_iterator it = con.begin();
	while (it != con.end())
	{
		cout << *it << " ";
		++it;
	}
}

附,自定义compare仿函数,控制比较结果;

class Date
{
	friend ostream& operator<<(ostream& _cout, const Date& d);
public:
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
	bool operator<(const Date& date) const
	{
		return (_year < date._year) ||
			(_year == date._year && _month < date._month) ||
			(_year == date._year && _month == date._month && _day < date._day);
	}
	bool operator>(const Date& date) const
	{
		return (_year > date._year) ||
			(_year == date._year && _month > date._month) ||
			(_year == date._year && _month == date._month && _day > date._day);
	}
private:
	int _year;
	int _month;
	int _day;
};

ostream& operator<<(ostream& _cout, const Date& date)
{
	_cout << date._year << "-" << date._month << "-" << date._day << endl;
	return _cout;
}

//自定义compare仿函数,控制比较结果
class pDateLess
{
public:
	bool operator()(const Date* pdate1, const Date* pdate2) 
	{
		return *pdate1 < *pdate2;
	}
};

int main()
{
	priority_queue<Date*, vector<Date*>, pDateLess> pq;
	pq.push(new Date(2000, 1, 1));
	pq.push(new Date(2001, 1, 1));
	pq.push(new Date(2002, 1, 1));
	while (!pq.empty())
	{
		cout << *pq.top();
		pq.pop();
	}
	return 0;
}

注:Date*,无法转化为const Date* &;

//const Date*&,是对类型const Date*的引用
//但实际传递的类型为Date*,无法转化为const Date* &
bool operator()(const Date*& pdate1, const Date*& pdate2) 
{
	return *pdate1 < *pdate2;
}

//说明
int a = 1;
int* pa = &a;
const int*& pb = pa; //报错int*无法转换为const int*&
//const引用非const对象
//首先int*会隐形转化为const int*, 需借助临时变量,临时变量具有常性


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++初阶 —— stack/queue 的相关文章

  • 优雅地实现 ExecutorServices 的队列长度指示器

    为什么 哦 为什么不java util concurrent为其提供队列长度指标ExecutorService是 最近我发现自己在做这样的事情 ExecutorService queue Executors newSingleThreadE
  • 使用 Tensorflow 对象检测 api 打乱训练数据集

    我正在使用 Faster RCNN 模型和 Tensorflow 对象检测 API 来开发徽标检测算法 我的数据集按字母顺序排列 因此有一百个阿迪达斯徽标 然后是一百个苹果徽标等 我希望在训练时对其进行洗牌 我在配置文件中添加了一些值 tr
  • 如何找到最大堆栈大小?

    我正在使用 Ubuntu 11 04 如何找出进程的最大调用堆栈大小以及堆栈的每个帧的大小 快速谷歌搜索应该会显示关于这个主题的一些信息 http www cs nyu edu exact core doc stackOverflow tx
  • 持久 Akka 邮箱和无损

    在 Akka 中 当一个 actor 在处理消息时死亡 内部onReceive 该消息丢失 有没有办法保证无损 有没有办法配置 Akka 始终保留消息before将他们发送到onReceive 以便在演员死亡时可以恢复并重播 也许像持久邮箱
  • 使用callstack在C中实现堆栈数据结构?

    我对 C 下内存结构的理解是 程序的内存与堆栈和堆分开 每个堆栈和堆都从块的两端生长 可以想象分配所有 RAM 但显然抽象为某种操作系统内存片段管理器 堆栈设计用于处理局部变量 自动存储 堆设计用于内存分配 动态存储 编者注 有一些 C 实
  • Node.js 中的作业队列

    我正在node js 中寻找一个可以由php 调用的作业队列管理器 这是一个需要发送电子邮件 创建 pdf 文件等的 Web 应用程序 我想对这些应用程序执行异步 php 进程 流程示例 用户请求 php 页面 Php调用作业队列管理器并添
  • 使用 Stacks Java 将中缀转换为 Postfix

    我正在尝试编写一个程序将中缀表达式转换为后缀表达式 我正在使用的算法如下 1 Create a stack 2 For each character t in the expression If t is an operand append
  • 需要帮助 Discord 机器人队列

    我一直在尝试为不和谐机器人和我的 gt q命令基本上工作为join play queue同时 问题是它只能同时对 2 首歌曲进行排队 所以我需要帮助使其对多首歌曲进行排队 queues check queue def check queue
  • 为什么堆上的内存分配比堆栈上的内存分配慢得多?

    我已经被告知很多次了 但我不知道为什么 从堆分配内存时会涉及哪些额外成本 与硬件有关吗 与CPU周期有关吗 这么多的猜测 但没有确切的答案 有人能给我一些详细说明吗 正如 unwind 所说 Heap数据结构比Stack更复杂 在我看来 当
  • 使用 sidekiq 处理两个独立的 Redis 实例?

    下午好 我有两个独立但相关的应用程序 他们都应该有自己的后台队列 阅读 单独的 Sidekiq 和 Redis 进程 然而 我希望偶尔能够将工作推给app2的队列来自app1 从简单的队列 推送的角度来看 如果app1没有现有的 Sidek
  • 修改栈上的返回地址

    我研究了缓冲区溢出漏洞的基础知识 并尝试了解堆栈是如何工作的 为此 我想编写一个简单的程序 将返回地址的地址更改为某个值 有人可以帮助我计算基指针的大小以获得第一个参数的偏移量吗 void foo void char ret char pt
  • std::stack 是否公开迭代器?

    是否std stack在 C STL 中公开底层容器的任何迭代器 还是应该直接使用该容器 根据堆栈的定义 堆栈没有迭代器 如果您需要带有迭代器的堆栈 则需要自己在其他容器 std list std vector 等 之上实现它 堆栈文档在这
  • 使用 Celery(RabbitMQ、Django)检索队列长度

    我在 django 项目中使用 Celery 我的代理是 RabbitMQ 我想检索队列的长度 我浏览了 Celery 的代码 但没有找到执行此操作的工具 我在 stackoverflow 上发现了这个问题 从客户端检查 RabbitMQ
  • TensorFlow 队列关闭后可以重新打开吗?

    我想将项目入队 关闭队列以确保其他会话将所有剩余项目出队 然后在下一个纪元稍后重新打开它 这可能吗 q tf FIFOQueue close q q close reopen q with tf Session as sess sess r
  • NOP 雪橇如何工作?

    我找不到回答这个问题的好来源 我知道 nop sled 是一种用于规避缓冲区溢出攻击中堆栈随机化的技术 但我无法理解它是如何工作的 有什么简单的例子可以说明这种方法 128 字节 nop sled 等术语是什么意思 有些攻击包括使程序跳转到
  • 使用java工具的类似Sidekiq的队列?

    我想要一个工作队列 其行为几乎与 ruby 的 sidekiq 完全相同 它不need使用 Redis 但它可以 我只是不能使用 ruby 甚至不能使用 Jruby 基本上 我希望能够创建使用某些参数运行的作业 并且工作池执行作业 工作人员
  • 使用一个或多个标准 FIFO 队列实现延迟队列 [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 延迟队列是一种队列 其中每条消息都有
  • printf() var-arg 引用如何与堆栈内存布局交互?

    给出代码片段 int main printf Val d 5 return 0 是否有任何保证编译器会存储 Val d and 5 连续地 例如 d l a V 5 Format String
  • Python多重处理使用队列写入同一文件

    我知道 Stack Exchange 上有很多与将多处理结果写入单个文件相关的帖子 并且我在阅读了这些帖子后就开发了我的代码 我想要实现的是并行运行 RevMapCoord 函数并使用 multiprocess queue 将其结果写入一个
  • Node Js:Redis 作业在完成其任务后未完成

    希望你们做得很好 我在我的 Nodejs 项目中实现了 BullMQ Bull 的下一个主要版本 来安排发送电子邮件的作业 例如 发送忘记密码请求的电子邮件 所以 我编写了如下所示的代码 用户服务 await resetPasswordJo

随机推荐

  • 求股票最大收益问题

    问题 xff1a 求股票最大收益 xff0c 股票每天的价格 xff1a 100 113 110 85 105 102 86 63 81 101 94 106 101 79 94 90 97 买进和卖出都在当天结束后进行 xff0c 在某一
  • Python pip 包的安装和卸载 使用。

    Python pip 包的安装和卸载 使用 xff08 一 xff09 pip 安装 一般 来说 Python 需要什么包 直接 pip install 包 即可 但是 这种方法太慢 因为他通过美国的服务器下载 提高 pip 速度 这里提供
  • jdk1.8安装和环境变量配置

    一 安装JDK 选择安装目录 安装过程中会出现两次 安装提示 第一次是安装 jdk xff0c 第二次是安装 jre 建议两个都安装在同一个java文件夹中的不同文件夹中 xff08 不能都安装在java文件夹的根目录下 xff0c jdk
  • python 读取PDF(tabula和pdfminer和pdfplumber的简单操作)

    一 pdfminer 读取PDF 官方文档 xff1a http www unixuser org euske python pdfminer 这里针对python3 1 模块安装 xff1a pip install i https pyp
  • 一区即将要洗的DVD片子

    101 Dalmatians Animated 2009 SE 101斑点狗 预计2009年发行特别版 12 Monkeys 05 10 2005 COM DOC 12只猴子 预计2005年5月10日发行扩展版 加评论和记录片等 2001
  • UML — 五大关系

    在UML教学视频中 xff0c 关系有四种 xff0c 而课本中有五种 xff0c 其实就是多加了一种 xff0c 那么下面我一并总结出来 1 关联关系 通俗点说就是关联关系就是两个对象他们之间的联系和关系 关联分两种 xff1a xff0
  • rhel6.5救援模式修复系统

    如果系统中很多重要的部分被删除了例如 boot下的所有东西 xff0c 则可以通过救援模式 root 64 dazzle1 桌面 mkdir backup root 64 dazzle1 桌面 cp etc fstab backup fst
  • 利用nvm安装npm失败的解决办法

    最近发现在安装nodejs后 xff0c 想使用npm发现自己的电脑上没有安装npm xff0c 可是网上都说安装了nodejs后会自动安装npm xff0c 找了很久解决办法发现没有合适的解决办法 xff0c 于是自己尝试了很久发现了问题
  • chrome 浏览器的缩略图怎么没有了?就是浏览过网页的缩略图,一点击就能打开网站。

    这个问题 xff0c 突然今天解决了 哈哈 分享 首先新标签页 点击左下角 最常访问的网站 点击 最常访问的网站 紧接着再点击被置顶端的 最常访问的网站 Ok xff0c 大功告成了 烦恼了几天的这个小功能 xff0c 有缩略图还是看着舒服
  • 史上最详细的PID教程——理解PID原理及优化算法

    Matlab动态PID仿真及PID知识梳理 云社区 华为云 huaweicloud com 位置式PID与增量式PID区别浅析 Z小旋 CSDN博客 增量式pid https zhuanlan zhihu com p 38337248 期望
  • ubuntu 20.04搭建samba文件共享服务器,实现基于Linux和Windows的共享文件服务

    ubuntu 20 04搭建samba文件共享服务器 xff0c 实现基于Linux和Windows的共享文件服务 超详细 一 xff0c samba的基本概念二 xff0c samba的安装三 xff0c samba的基本配置创建文件夹更
  • ERROR: Could not find a version that satisfies the requirement torchvision

    打docker时出错 xff0c ERROR Could not find a version that satisfies the requirement torchvision from versions 0 1 6 0 1 7 0 1
  • openstack 常用命令回顾及总结

    1 概述 命令实际执行基于OpenStack Queens版本 xff0c 更高版本亦可 xff0c 长时间未使用openstack有些遗忘 xff0c 整理后方便自己回顾学习 xff0c 仅供各位参考 xff0c 详细命令及参数可以参考o
  • TPMS方案 传感器 infineon篇 (SP35 SP37)

    TPMS方案 xff08 SP35 SP37 xff09 传感器 infineon篇 关于sp37无压力芯片目前已有方案 关于sp35传感器已经稳定出货 xff0c 欢迎咨询 硬件原理图 软件说明 xff1a 协议 调制方式 FSK 频率
  • sudo rosdep init 出现 ERROR: cannot download default sources list from:

    sudo rosdep init 出现 ERROR cannot download default sources list from 针对目前安装ROS出现一下指令的错误 span class token function sudo sp
  • 新装linux主机可以ping通,但是SSH无法登陆

    0 xff0c 新装一台linux主机 xff0c 可是ssh连接不上 xff0c 能ping通 怎么办呢 xff1f 1 xff0c 先查看一下防火墙状态 sudo ufw status 2 xff0c 关闭防火墙 sudo ufw di
  • tcp头以及ip头

    转自http www cnblogs com zzq919101 p 7866550 html 在网上找了很多有关tcp ip头部解析的资料 xff0c 都是类似于下面的结构 抽象出图文是这种结构 xff0c 但是在底层中数据到底是怎么传输
  • C++初阶 —— 入门/概念

    目录 一 xff0c 关键字 xff08 C 43 43 98 xff09 二 xff0c 命名空间 命名空间定义 命名空间使用 三 xff0c C 43 43 输入 输出 四 xff0c 缺省参数 五 xff0c 函数重载 六 xff0c
  • C++初阶 —— list类

    目录 一 xff0c list介绍 二 xff0c list的使用 构造函数 list iterator的使用 list capacity list element access list modifiers list迭代器失效 三 xff
  • C++初阶 —— stack/queue

    目录 一 xff0c 容器适配器 deque双端队列 二 xff0c stack栈 stack接口 stack模拟实现 三 xff0c queue队列 queue接口 queue模拟实现 四 xff0c priority queue优先级队