stack和queue

这篇具有很好参考价值的文章主要介绍了stack和queue。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

💓博主个人主页:不是笨小孩👀
⏩专栏分类:数据结构与算法👀 C++👀 刷题专栏👀 C语言👀
🚚代码仓库:笨小孩的代码库👀
⏩社区:不是笨小孩👀
🌹欢迎大家三连关注,一起学习,一起进步!!💓

stack和queue,C++,数据结构,c++

容器适配器

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

stack和queue,C++,数据结构,c++

虽然stack和queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为stack和队列只是对其他容器的接口进行了包装,STL中stack和queue默认使用deque。

stack和queue,C++,数据结构,c++

stack和queue,C++,数据结构,c++
stack和queue,C++,数据结构,c++

deque

简单介绍一下deque,了解一下就可以。
deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组。

stack和queue,C++,数据结构,c++
stack和queue,C++,数据结构,c++

与vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素,因此其效率是必vector高的。
与list比较,其底层是连续空间,空间利用率比较高,不需要存储额外字段。
但是,deque有一个致命缺陷:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构时,大多数情况下优先考虑vector和list,deque的应用并不多,而目前能看到的一个应用就是,STL用其作为stack和queue的底层数据结构。

为什么选择deque作为默认容器呢?

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的优点,而完美的避开了其缺陷。

stack

stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。
2. stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定 的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。
3. stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持以下 操作: empty:判空操作 back:获取尾部元素操作 push_back:尾部插入元素操作 pop_back:尾部删除元素操作。
4. 标准容器vector、deque、list均符合这些需求,默认情况下,如果没有为stack指定特定的底层容器, 默认情况下使用deque。

stack和queue,C++,数据结构,c++

模拟实现:

实现对于现阶段的大家来说,应该不是什么难事,代码给大家奉上。

template <class T, class container = deque<T>>
	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;
	};

queue

  1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端 提取元素。
  2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的 成员函数来访问其元素。元素从队尾入队列,从队头出队列。
  3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操 作: empty:检测队列是否为空 size:返回队列中有效元素的个数 front:返回队头元素的引用 back:返回队尾元素的引用 push_back:在队列尾部入队列。
    pop_front:在队列头部出队列
  4. 标准容器类deque和list满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标 准容器deque。

stack和queue,C++,数据结构,c++

模拟实现

和stack一样,逻辑大家不懂得可以看之前的数据结构。代码给大家奉上。

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

		bool empty()
		{
			return con.empty();
		}
	private:
		Container con;
	};

priority_queue(优先级队列)

  1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。
  2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元 素)。
  3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特 定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。
  4. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭 代器访问,并支持以下操作:
    empty():检测容器是否为空
    size():返回容器中有效元素个数
    front():返回容器中第一个元素的引用
    push_back():在容器尾部插入元素
    pop_back():删除容器尾部元素
  5. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指
    定容器类,则使用vector。
  6. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数 make_heap、push_heap和pop_heap来自动完成此操作。

优先级队列就是我们之前讲的堆了,为什么叫优先级队列,因为它比较好理解吧。

stack和queue,C++,数据结构,c++

优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。注意:默认情况下priority_queue是大堆。

这里面牵扯到一个仿函数的问题
stack和queue,C++,数据结构,c++

仿函数可以很好的解决C语言中函数指针的问题,仿函数只要一个类重载了()这个运算符,就可以算是一个仿函数了。

stack和queue,C++,数据结构,c++
less默认的是小于,而greater是大于,库里也已经帮我们实现好了。

stack和queue,C++,数据结构,c++
stack和queue,C++,数据结构,c++

模拟实现

我们可以利用仿函数的方式通过传入的参数,来控制大堆和小堆,逻辑和堆的实现一样,直接看代码。

	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)
		{
			con(first, last);
			for (int i = (con.size() - 1 - 1 / 2); i >= 0; i--)
			{
				adjust_down(i);
			}
		}

		void adjust_up(size_t child)
		{
			size_t parent = (child - 1) / 2;
			while (child > 0)
			{
				//if (con[child] > con[parent])
				if(cmp(con[parent],con[child]))
				{
					swap(con[child], con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		void adjust_down(size_t parent)
		{
			size_t child = parent * 2 + 1;
			while (child < con.size())
			{
				//if (child + 1 < con.size() && con[child] < con[child + 1])
				if (child+1 < con.size()&&cmp(con[child],con[child+1]))
				{
					child++;
				}

				if (cmp(con[parent], con[child]))
				{
					swap(con[child], con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}

		void push(const T& x)
		{
			con.push_back(x);
			adjust_up(con.size()-1);
		}

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

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

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

	private:
		Container con;
		Compare cmp;
	};

在默认情况下,是大堆。小堆的话需要我们自己传greater仿函数。

那么今天的分享就到这里了,有什么不懂得可以私信博主,或者添加博主的微信,欢迎交流。文章来源地址https://www.toymoban.com/news/detail-721509.html

到了这里,关于stack和queue的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构:队列Queue详解

    队列 :只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表。进行插入操作的一端称为 队尾 ,删除操作的一端称 队头 。 入队列 :进行插入操作的一端称为 队尾 。 出队列 :进行删除操作的一端称为 队头 。 在 Java 中, Queue是个接口,底层是通过链表

    2024年02月11日
    浏览(28)
  • 数据结构之Queue的实现

    方法名 参数 功能 返回 Size void 返回链表规模(该方法由List T派生而来) empty void 返回链表是否为空(该方法由List T派生而来) front void 返回队首数据域的引用 enqueue T const e 入队 void dequeue void 出队 出队的对象

    2024年02月15日
    浏览(31)
  • 数据结构---栈(Stack)

    栈是一种 线性 数据结构 栈是\\\" 后进先出 (LIFO---Last In First Out)\\\"的数据结构(盘子的叠放:当服务员将新的盘子放在餐桌上时,他们通常会将盘子放在已有的盘子堆的顶部。当顾客用完盘子后,服务员会从堆顶取走盘子。这个过程就类似于栈的入栈和出栈操作。) 规定只能从 栈顶

    2024年01月21日
    浏览(31)
  • 数据结构——栈(Stack)

    目录 1.栈的介绍 2.栈工程 2.1 栈的定义 2.1.1 单链表实现栈 2.1.2 数组实现栈 2.1.2.1 静态数组栈 2.1.2.2 动态数组栈 2.2 栈的函数接口 2.2.1 栈的初始化 2.2.2 栈的数据插入(入栈) 2.2.3 栈的数据删除(出栈) 2.2.4 判断栈是否为空 2.2.5 取栈顶数据 2.2.6 栈数据统计 2.2.7 栈销毁 3. 栈总

    2024年01月21日
    浏览(34)
  • 【数据结构】队列(Queue)的实现 -- 详解

    1、概念 队列 :只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有 先进先出 FIFO(First In First Out)。 入队列 :进行 插入 操作的一端称为 队尾 。 出队列 :进行 删除 操作的一端称为 队头 。 2、结构 (1)队列的顺序存储结构 入队 ,不需要

    2024年02月15日
    浏览(28)
  • [数据结构 -- C语言] 队列(Queue)

    目录 1、队列 1.1 队列的概念及结构 2、队列的实现 2.1 接口 3、接口的实现 3.1 初始化队列 3.2 队尾入队列 分析: 3.3 队头出队列 分析: 3.4 获取队列头部元素 3.5 获取队列尾部元素 3.6 获取队列中有效元素个数 3.7 检测队列是否为空 3.7.1 int 类型判空 3.7.2 bool 类型判空 3.8 销毁队

    2024年02月07日
    浏览(30)
  • 【数据结构】栈(Stack)实现详解

    🚩 纸上得来终觉浅, 绝知此事要躬行。 🌟主页:June-Frost 🚀专栏:数据结构 🔥该文章主要了解实现栈的相关操作。  栈是一种特殊的线性表,其只允许在 固定的一端 进行插入和删除元素操作。 进行数据插入和删除操作的一端称为栈顶,另一端称为栈底 。栈中的数据元

    2024年02月08日
    浏览(31)
  • 【Golang】实现简单队列(Queue)数据结构

     在计算机科学中,队列是一种特殊的线性数据结构,它遵循FIFO(先进先出)原则。队列中的元素只能从一端(称为队尾或后端)添加,并且只能从另一端(称为队头或前端)移除。这种特性使得队列在许多算法和数据结构中都有广泛的应用,例如操作系统中的任务调度、网

    2024年01月19日
    浏览(30)
  • Java 数据结构之队列(Queue)详解

    目录 1、在Java中有哪些常见的队列? 2、Queue 接口分析 3、Deque 接口分析 4、PriorityQueue 的实现原理详解 5、使用Java数组实现队列的简单示例 1、在Java中有哪些常见的队列?         在Java中,有一些常见的队列实现。下面是其中一些的列举: //队列也是一种线性的数据结构

    2024年02月15日
    浏览(30)
  • 【数据结构】栈(Stack)的实现 -- 详解

    1、概念 栈 :一种特殊的线性表,其只允许在表尾进行插入和删除元素操作。 进行数据插入和删除操作的一端称为栈顶,另一端称为栈底 。栈中的数据元素遵守后进先出 LIFO(Last In First Out)的原则。 压栈 :栈的插入操作叫做进栈 / 压栈 / 入栈, 入数据在栈顶 。 出栈 :栈

    2024年02月14日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包