C++·栈和队列

       栈和队列是什么看这里:

数据结构·栈和队列-CSDN博客文章浏览阅读948次,点赞25次,收藏26次。本节讲解了栈和队列的内容,其核心就是栈的特点是后进先出,队列的特点是先进先出。并用C语言实现了栈和队列的结构以及它们的各种接口https://blog.csdn.net/atlanteep/article/details/136071056?spm=1001.2014.3001.5501

        准确的来说栈和队列并不是一种容器,而是容器适配器,可以看到他们的第二个参数传的都不是空间配置器,而是另一个东西。不过因为第二个参数是一个缺省参数,因此这并不影响我们正常使用他们。

        

1. stack 栈      

        官网资料:stack - C++ Reference

        

        这是栈的所有成员函数,emplace我们先不关心,其他成员函数我们都懂是什么意思。

        其中top就是取栈顶元素,会返回栈顶元素的引用。

        swap交换两个栈中的元素。

                

        可以看到,非常的后进先出。

2. queue 队列

        官网资料:queue - C++ Reference

        成员函数:

        栈和队列成员函数都一样,只是队列中用front返回队头的引用

                

        可以看到,非常的先进先出。

3.  容器适配器

        一开始我们提到过栈和队列都是容器适配器,这个容器适配器的功能就是不用我们自己手动去实现栈和队列,而是借助其他容器进行生成。比如果我们在顺序表外套一层外壳,让这个容器只支持尾插尾删,那不就相当于将顺序表适配成了栈。

3.1 容器适配器使用

        当然在实际写栈的时候我们不能将栈的底层写死成顺序表,因为链表或别的容器结构也可以当作栈的底层。

                                

        为了解决这一问题,我们可以在添加一个模板参数Container

                        

        然后用这个位置的容器生成它的对象,再用这个对象的操作函数来完善整个stack。首先明确一点,就是因为成员变量是自定义类型,因此我们不用写stack的构造函数等,因为电脑会自动生成这些函数,调用自定义类型中的构造函数来构造stack类型。

        因此我们直接实现stack的各种功能

                        

        当然,如果 _con 这个容器不支持比如 push_back pop_back 这些操作,那生成的栈的时候就会报错,说明这个容器无法适配。

        可以看到,我们将一个数据结构封装之后就形成了一个新的数据结构,可以体会一下这个过程。

        下面我们验证一下自己写的栈:

        ​​​​​​​        ​​​​​​​

        那么在STL库中模板参数被给到一个缺省值 deque<T> ,模板参数也是参数因此我们也可以给我们自己写的模板加上缺省值,这样就可以不给第二个模板参数了

3.2 deque<T> 双端队列

        官网资料:deque - C++ Reference

        可以看到,list链表没有的 [ ] 访问,vector顺序表没有的 _front 修改,在deque双端队列中同时都被支持了,所以说deque是list和vector的结合体。

        

3.2.1 deque的原理介绍

        deque首先是有一个中控数组,中控数组中的每个元素都是一个数组指针,指向各个buffer(缓冲)数组,deque容器中的数据内容都存储在buffer数组中。这样的话deque容器就同时包含了连续存储和链式存储的两个特点了。

        如果想要头插数据,就在头创建个buff数组,用中控数组将新buffer数组和旧数组统一维护进deque容器中,也就是说只用给中控数扩容头插一下,从而避免了像vector那样头插数据时要将后面的所有数据都向后挪动。

        当想查找元素的时候,比如,如果buffer数组长度都统一成10,我们想查找第25个元素的内容是什么,25/10得出所在第几个buffer数组,25%10得出在此buffer数组的第几位上。

        当然,看到这里大家就肯定已经能发现deque容器结构的诸多弊端了:1. 如果在容器中间insert一个数据的时候后面的所有数据要不要挪动,还是将所处buffer数组扩容;2. 那如果各个buffer数组的长度不同,[ ] 查找元素的时候将要一个一个的统计buffer数组长度,最后才能找到元素处在第几个buffer数组,这样的话 [ ] 下标访问操作的速度远不及vector的访问速度;3. 与list容器排序时拥有同样的问题,就是当 [ ] 下标访问效率不高的情况下,给容器中数据排序时的效率也会及低。

        ps: 这里提醒一下,算法库中的sort要求传随机迭代器,而list容器是双向迭代器,因此在给list容器内容排序时,只能用list容器自己的成员函数,不过值得放心的是deque是随机迭代器。

        但是deque也有自己的优势,它的头插头删效率远高于vector,因为支持 [ ] 因此数据访问也比list快一点,所以当我们需要大量头插头删少量数据元素访问时,deque就是不错的选择,也就是说stack和queue使用deque当默认适配器就很不错。

        

4. priority_queue 优先级队列

        官网资料:priority_queue - C++ Reference

        优先级队列不是一个队列,只是这个名字这么叫的,priority_queue会保证第一个数据永远是优先级最高的数据。

        priority_queue的底层是一个堆,我们观察它的三个模板参数,第一个指示优先级队列中存储数据的类型,第二个参数因为底层是堆,所以用vector来适配,第三个参数是一个仿函数,它的缺省参数保证了这个堆是大根堆。

        这是priority_queue的所有成员函数,和stack与queue的很类似。

        这里要提醒一下,在构造容器的时候不止可以使用迭代区间来构造,当源是数组的时候我们可以直接使用原生指针,只要是连续的空间就可以这么构造。

        这里我们给迭代区间或者原生指针区间构造的话,priority_queue就直接去建堆了。

        我们可以从调试中看出来,把数据一股脑放进去然后priority_queue直接就是建堆了。

        如果我们把第三个模板参数改成great仿函数就是建小堆

        这里我们可以联系堆排序来记忆,sort算法中,less仿函数作为缺省参数用来排升序,排升序建大根堆;greater相反排降序,降序建小根堆。

        在C++中没用专门的堆结构,因为可以说优先级队列就是堆,所以当我们需要使用堆的时候去使用priority_queue就可以了。

4.1 priority_queue 的实现

        仿函数的问题我们一会再说,现在先不用仿函数,把优先级队列的适配框架化出来

        

        关于堆的结构以及建堆等问题详见:​​​​​​​数据结构·二叉树(一)_生成4个4层的满二叉树r1, r2, r3, r4,然后把4颗树的根节点串起来-CSDN博客文章浏览阅读1k次,点赞24次,收藏23次。本节介绍了二叉树的概念,基于完全二叉树引出了堆的概念,并着手实现了一个小根堆,最后我们介绍了堆应用中的堆排序和TOP-K问题,堆排序的时间复杂度是跟快排一个量级的,很有意思_生成4个4层的满二叉树r1, r2, r3, r4,然后把4颗树的根节点串起来https://blog.csdn.net/atlanteep/article/details/136437696

4.1.1 push pop

        push一个一个数据的插入建堆,用到向上调整算法建堆

        ​​​​​​​        

        pop删除堆顶数据要先将堆顶和最后一个数据调换位置,删掉调换后的最后一个数据,再把现在的堆顶元素向下调整落位。

                

        我这个pop的写法有点麻烦,还是用二叉树那节里的假设法简单一点

        

4.1.2 top size empty

        ​​​​​​​        ​​​​​​​        

4.1.3 迭代区间构造

                

        这里我们先一股脑把数据都存进_con顺序表中,然后向下建堆,而不选择一个一个数据存进去向上建堆,毕竟O(N)与O(N*logN)的差距还是有的。

        因为写了一种构造了,所以编译器不会自动生成默认构造了,于是我们用第一行代码强制让编译器生成默认构造。

4.2 仿函数

        到这里优先级队列的实现就基本完成了,但是还有一个缺陷没解决,就是我们现在写的这个只能建大堆,太死板了,因此下面我们下面要通过仿函数来彻底解决这一问题。

4.2.1 基本概念

        仿函数,也叫函数对象,它是一个重载了圆括号 operator() 的类,类的对象可以像函数一样使用。

        ​​​​​​​        ​​​​​​​        

        比如上面这段代码,我们重载了 () 操作符之后,让Func实例化出来的f1对象使用这个重载了的操作符,就使得这个对象看起来像是一个函数名,整个操作看起来就像是使用了一个传参了的函数。

4.2.2 仿函数应用

        下面我们写一个自己的less仿函数,给它加上模板参数,用来适配多种类型变量的比较

        ​​​​​​​                

        我们知道C语言中的qsort函数,是通过传函数指针来确定排升序还是降序的,但是C++中并不喜欢用函数指针,而是用仿函数取而代之,而priority_queue的第三个参数,也就是那个仿函数就起到了与qsort中那个函数指针类似的作用。

        下面我们实现一下代码,需要修改的位置只有3个地方,就是容器模板,向上调整的比较规则和向下调整的比较规则。

​​​​​​​ ​​​​​​​

        ​​​​​​​        ​​​​​​​                

        下面我们测试一下可不可行

        很明显,仿函数的使用成功起到应有的作用了。

4.3 priority_queue实现代码

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

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

template<class T, class Container = vector<T>, class Compare = my_less<T>>
class priority_queue
{
public:
	priority_queue() = default;
	template<class InputIterator>
	priority_queue(InputIterator first, InputIterator last)
	{
		while (first != last)
		{
			_con.push_back(*first);
			++first;
		}
		//建堆算法
		//最后一个非叶子节点
		int parent = (_con.size() - 2) / 2;
		while (parent >= 0)
		{
			adjustdown(parent);
			--parent;
		}
	}

	void adjustup(int child)
	{
		Compare compfunc;
		int parent = (child - 1) / 2;
		while (child > 0)
		{
			//默认建大堆
			//if (_con[parent] < _con[child])
			if (compfunc(_con[parent], _con[child]))
			{
				swap(_con[child], _con[parent]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
				break;
		}
	}
	void push(const T& x)
	{
		_con.push_back(x);
		adjustup(_con.size() - 1);
	}

	void adjustdown(int parent)
	{
		Compare compfunc;
		int l_child = parent * 2 + 1;
		int r_child = l_child + 1;
		int sz = _con.size() - 1;
		while (l_child <= sz)
		{
			if (r_child <= sz)//右孩子存在
			{
				//if (_con[l_child] < _con[r_child])
				if (compfunc(_con[l_child], _con[r_child]))
				{
					//右孩子大
					//if (_con[parent] < _con[r_child])
					if (compfunc(_con[parent], _con[r_child]))
					{
						swap(_con[r_child], _con[parent]);
						parent = r_child;
						l_child = parent * 2 + 1;
						r_child = l_child + 1;
						continue;
					}
				}
				//左孩子大
			}
			//只有左孩子
			//if (_con[parent] < _con[l_child])
			if (compfunc(_con[parent], _con[l_child]))
			{
				swap(_con[l_child], _con[parent]);
				parent = l_child;
				l_child = parent * 2 + 1;
				r_child = l_child + 1;
				continue;
			}
			//左右孩子都比父小
			break;
		}
	}
	void pop()
	{
		swap(_con[0], _con[_con.size() - 1]);
		_con.pop_back();  
		adjustdown(0);
	}

	const T& top()
	{
		return _con[0];
	}
	size_t size()
	{
		return _con.size();
	}
	bool empty()
	{
		return _con.empty();
	}

private:
	Container _con;
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度解析移动硬盘“函数不正确”错误及高效恢复策略

在数据密集型的社会中&#xff0c;移动硬盘作为移动存储的重要载体&#xff0c;承载着无数用户的个人信息、工作资料及珍贵回忆。然而&#xff0c;当遭遇“函数不正确”的错误时&#xff0c;这些宝贵的数据仿佛被一层无形的屏障所阻隔&#xff0c;让人束手无策。本文将深入探讨…

SiCat:一款多功能漏洞利用管理与搜索工具

关于SiCat SiCat是一款多功能漏洞利用管理与搜索工具&#xff0c;该工具基于纯Python 3开发&#xff0c;旨在帮助广大研究人员有效地识别和收集来自开源和本地存储库的漏洞信息。 SiCat专注于网络安全管理方面的实践工作&#xff0c;允许研究人员快速实现在线搜索&#xff0c;…

关于centos7自带的nginx1.20.1开启https后,XP系统的IE6和IE8无法显示网页的问题

CentOS7自带的nginx-1.20.1是支持HTTP/2和TLS1.3的。 软件包名称&#xff1a;nginx-1.20.1-10.el7.x86_64 CentOS7默认开启了HTTP/2&#xff0c;但没有开启TLS1.3&#xff0c;以及IE6和IE8的https访问。 开启方法&#xff1a; ssl_ciphers HIGH:!aNULL:!MD5;改为ssl_ciphers…

新增多种图表类型,新增插件管理模块,DataEase开源数据可视化分析工具v2.8.0发布

2024年7月8日&#xff0c;人人可用的开源数据可视化分析工具DataEase正式发布v2.8.0版本。 这一版本的功能变动包括&#xff1a;图表方面&#xff0c;新增组合图、热力地图、符号地图、K线图等图表类型&#xff0c;并对已有的仪表盘、明细表、指标卡、富文本等图表类型进行了功…

非参数检测5——双输入检测系统

在很多情况下&#xff0c;信号常常存在于两个带有独立噪声的信道中。所以很有必要研究双输入系统。双输入系统广泛应用于无线电天文学、水下声波检测和地球物理学等领域。

SpringBoot拦截器

目录 一、拦截器快速入门 &#xff08;1&#xff09;什么是拦截器 &#xff08;2&#xff09;拦截器的使用步骤 1、定义拦截器 &#x1f340;preHandle() 方法 &#x1f340;postHandle() 方法 &#x1f340;afterCompletion() 方法 2、注册配置拦截器 二、拦截器详解…

43、nginx的优化、防盗链、重定向、代理

nginx的优化、防盗链、重定向、代理 一、nginx的优化 1.1、隐藏版本号 server_tokens off;隐藏版本号 [roottest1 conf]# vim nginx.confserver_tokens off;[roottest1 conf]# nginx -t nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok ngin…

顾客排队购买蛋挞问题(算法与数据结构设计)

课题内容和要求 顾客排队买蛋挞问题。有N个顾客排队&#xff0c;每人最多买M个。烘焙员每次烘焙1到K个蛋挞放入盘中&#xff0c;顾客只能购买盘中的蛋挞&#xff0c;未达到M个需重新排队。输出每个顾客购买情况和完成顺序。 例如—— 输入&#xff1a;N9&#xff0c;K5&#x…

Linux安装elasticsearch单机版

一、检查内核 uname -a uname -m 二、下载版本 下载版本选择自己服务器相同的内核版本 我这边是aaech64 ES下载地址 Kibana 下载地址 二、上传服务器解压 tar -xvf elasticsearch-8.14.1-linux-aarch64.tar.gz 三、安装ES 因为ES不能用root用户启动先创建用户 #新增 es …

Django QuerySet对象,all()方法

all()方法 在Django中&#xff0c;all()方法是QuerySet对象的一个方法&#xff0c;用于获取模型的所有实例。 当你调用ModelName.objects.all()时&#xff0c;Django会生成一个SQL查询&#xff0c;从数据库中获取该模型的所有记录&#xff0c;并返回一个QuerySet对象&#xf…

【产品运营】Saas的核心六大数据

国内头部软件公司的一季度表现惨不忍睹&#xff0c;为啥美国的还那么赚钱呢&#xff1f;其实核心是&#xff0c;没几个Saas产品经理是看数据的&#xff0c;也不知道看啥数据。 SaaS 行业&#xff0c;天天抛头露面、名头叫的响的 SaaS 产品&#xff0c;真没有几个赚钱的。 那为…

中国计量大学理学院访问赛氪网:共探校企合作新篇章来

2024年7月5日&#xff0c;中国计量大学理学院代表团莅临环球赛乐&#xff08;北京&#xff09;科技有限公司&#xff0c;进行了一场深入的调研交流活动。代表团成员包括中国计量大学理学院副院长王义康教授、数据科学系副主任刘学艺副教授以及金世举老师。此次访问旨在进一步强…

江洲的《家书》,岂止抵万金

题记 今晨6点钟&#xff0c;像往日一样的背上鱼具包&#xff0c;欲驾乘清凉舒适的晨风&#xff0c;前往味江河堤享受钓翁乐趣。孰料开门一看&#xff0c;朦胧的天空竟下着淅淅沥沥的小雨。 今年的天气异常&#xff0c;是笔者寄居“西川第一天”古镇5年来所未见&#xff1a;再…

stm32——外部中断EXTI

上回书说到定时器的级联&#xff0c;今天来谈谈外部中断EXTI。我使用的是STM32F103C8T6的学习板。仅供大家参考。 什么是中断呢&#xff1f;中断是指计算机在执行程序的过程中&#xff0c;当出现某些异常情况或特殊事件&#xff08;例如外部设备请求、定时时间到达、程序错误等…

YOLOV8花朵实例分割实战

原文:YOLOV8花朵实例分割实战 - 知乎 (zhihu.com) 一、代码: https://github.com/ultralytics/ultralytics​github.com/ultralytics/ultralytics 与先前几个版本相比,YOLOv8 模型更快、更准确,同时为训练模型提供统一框架,以执行以下基本任务: 目标检测;实例分割;图…

奇安信20240513笔试

题目一 解题思路 n转为字符串&#xff0c;如果位数为偶数&#xff0c;取前一半设为x&#xff0c;后一段为y&#xff0c;从x最低位开始&#xff0c;9&#xff0c;9*10&#xff0c;9*10*10。。。 到最高位&#xff0c;加x&#xff0c;如果x大于或等于y&#xff0c;加1. 位数为奇数…

武汉免费 【FPGA实战训练】 Vivado入门与设计师资课程

一&#xff0e;背景介绍 当今高度数字化和智能化的工业领域&#xff0c;对高效、灵活且可靠的技术解决方案的需求日益迫切。随着工业 4.0 时代的到来&#xff0c;工业生产过程正经历着前所未有的变革&#xff0c;从传统的机械化、自动化逐步迈向智能化和信息化。在这一背景下&…

全志A527 T527 cat /proc/cupinfo没有Serial问题

1.前言 我们有些客户是使用cpuinfo节点去获取系统的cpuid的,如下: cat /proc/cupinfo processor : 0 BogoMIPS : 48.00 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp CPU impleme…

代码随想录-Day51

115. 不同的子序列 给你两个字符串 s 和 t &#xff0c;统计并返回在 s 的 子序列 中 t 出现的个数&#xff0c;结果需要对 109 7 取模。 示例 1&#xff1a; 输入&#xff1a;s “rabbbit”, t “rabbit” 输出&#xff1a;3 解释&#xff1a; 如下所示, 有 3 种可以从 …

基于 LlamaIndex、Claude-3.5 Sonnet 和 MongoDB,构建具有超级检索能力的智能体

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对大模型技术趋势、算法项目落地经验分享、新手如何入门算法岗、该如何准备面试攻略、面试常考点等热门话题进行了深入的讨论。 总结链接如…