【C++】容器篇(四)—— queue的基本介绍以及模拟实现

这篇具有很好参考价值的文章主要介绍了【C++】容器篇(四)—— queue的基本介绍以及模拟实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:

在上期博文中我带大家对stack进行深入的学习,本期我将带领学习的是关于 queue的基本知识,并且还将给大家介绍并实现  priority_queue。接下来,让我们正式本期的内容。


目录

(一)queue的基本介绍

(二)基本使用

(三)模拟实现

(四)priority_queue的基本介绍

(五)基本使用

(六)priority_queue的模拟实现

(六)deque的简单介绍(了解)

1、deque的原理介绍

2、deque的缺陷

(七)deque作为stack和queue的底层默认容器

1、分析

2、deque的优势

3、原因

总结


(一)queue的基本介绍

  • 文档链接:queue的文档介绍

 💨  queue是一个容器适配器,它是基于deque或者list实现的。queue的特点是先进先出(FIFO)

底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:

  1. empty:检测队列是否为空
  2. size:返回队列中有效元素的个数
  3. front:返回队头元素的引用
  4. back:返回队尾元素的引用
  5. push_back:在队列尾部入队列
  6. pop_front:在队列头部出队列

标准容器类deque和list满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque

【C++】容器篇(四)—— queue的基本介绍以及模拟实现


 

(二)基本使用

  • queue的主要的接口函数大概就是以下这几个,我们也将围绕这几个接口来模拟实现。

【C++】容器篇(四)—— queue的基本介绍以及模拟实现


(三)模拟实现

  • 代码如下:
#pragma once
namespace zp
{
	template<class T, class Container = deque<T>>
	class queue
	{
	public:
		void push(const T& x)
		{
			return _qq.push_back(x);
		}

		void pop()
		{
			if (!_qq.empty())
			{
				return _qq.pop_front();
			}
		}

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

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

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

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

	private:
		Container _qq;
	};

	void test_queue_1()
	{
		queue<int> q;
		//queue<int, list<int>>q;
		//queue<int, vector<int>>q;
		q.push(1);
		q.push(2);
		q.push(3);
		q.push(4);
		q.push(5);


		//队首元素
		if ((!q.empty()))
		{
			cout << q.front() << " "<<endl;
		}
	
		q.pop();
		cout << q.front() << endl;

		// 检查队列是否为空
		if (q.empty())
		{
			cout << "Stack is empty" << endl;
		}
		else
		{
			cout << "queue is not empty" << endl;
		}

		// 获取队列的大小
		cout << "queue size is " << q.size() << endl;

		//输出队列元素
		while (!q.empty())
		{
			cout << q.front() << " ";
			q.pop();
		}
		cout << endl;
	}
}

 

(四)priority_queue的基本介绍

  • 文档链接:priority_queue的文档介绍

priority_queue是一个容器适配器,它是基于vector实现的,默认情况下是按照元素大小排序的(大根堆)。可以通过指定比较函数改变排序方式。

底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭 代器访问,并支持以下操作:

  1. push():元素入队
  2. pop():元素出队
  3. top():返回堆顶元素
  4. empty():判断堆是否为空
  5. size():返回堆中元素数量

 💨  大家如果想了解更多,可以借助文档仔细琢磨!!!


(五)基本使用

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

基本使用跟上面的queue是大同小异的,我们直接模拟实现即可。

⚔️  注意: 默认情况下priority_queue是大堆。⚔️ 


(六)priority_queue的模拟实现

  • 代码如下:
#pragma once
namespace zp
{
    template<class T, class Compare = less<T>>
    class priority_queue 
    {
    public:
        void push(const T& val) 
        {
            _qq.push_back(val);
            push_heap(_qq.begin(), _qq.end(), _cmp);
        }

        void pop() 
        {
           pop_heap(_qq.begin(), _qq.end(), _cmp);
           _qq.pop_back();
        }

        const T& top() const 
        {
            return _qq.front();
        }

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

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

    private:
        vector<T> _qq;
        Compare _cmp;
    };

    void test_priority_queue()
    {
        priority_queue<int> pq;
        pq.push(1);
        pq.push(3);
        pq.push(2);
        pq.push(5);
        pq.push(4);

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

(六)deque的简单介绍(了解)

  • 文档链接:deque文档介绍

1、deque的原理介绍

deque(双端队列)

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

【C++】容器篇(四)—— queue的基本介绍以及模拟实现

deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组,其底层结构如下图所示:

【C++】容器篇(四)—— queue的基本介绍以及模拟实现

 

双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落在了deque的迭代器身上,因此deque的迭代器设计就比较复杂,如下图所示:

 【C++】容器篇(四)—— queue的基本介绍以及模拟实现


那deque是如何借助其迭代器维护其假想连续的结构呢?

  1. deque是一个由多个固定大小的缓冲区构成的序列容器,每个缓冲区都被当作一个元素来处理。为了维护deque的假想连续结构,deque的迭代器实际上是一种复合迭代器,它将多个子迭代器封装在一起,以提供对整个deque的访问。
  2. 具体来说,deque的迭代器实际上就是一个指向数据缓冲区的指针数组,每个指针指向一个单独的存储块,而这些存储块构成了deque的数据缓冲区。

【C++】容器篇(四)—— queue的基本介绍以及模拟实现

 

  1. deque会通过维护多个内部的缓冲区来实现假想连续的结构,并且迭代器也会对这些内部缓冲区进行适当划分和处理;
  2. 在deque内部,每个缓冲区被称作一个节点node,并在其内部维护了一个完整的数据块;
  3. 当deque在两端插入/删除元素时,它会动态重新分配节点,使得每个节点上的数据块都可以被利用,从而保证数据块是假想连续的。同时,迭代器会利用这些节点间的相对偏移量来实现对deque的高效遍历。

下面是一个简单的示例程序,演示了如何使用deque迭代器来访问deque中的元素:

#include <iostream>
#include <deque>
using namespace std;

int main() 
{
   deque<int> d = { 0,1, 2, 3, 4 };
   deque<int>::iterator it = d.begin();

    // 使用迭代器访问deque
    for (; it != d.end(); ++it) {
        cout << *it << " ";
    }
   cout <<endl;

    // 在头部和尾部插入元素
    d.push_front(6);
    d.push_back(5);

    // 再次使用迭代器访问deque
    for (it = d.begin(); it != d.end(); ++it) {
        cout << *it << " ";
    }
   cout << endl;

    return 0;
}

解释说明:

  1. 在上述代码中,我们使用deque容器和迭代器来存储和访问一系列整数;
  2. 首先,我们定义了一个deque对象d,并使用begin()函数获取其头部的迭代器;
  3. 然后,我们使用迭代器遍历deque中的元素,并输出它们的值;
  4. 接下来,我们调用push_front()函数和push_back()函数在deque的头部和尾部插入两个新元素;
  5. 最后,我们再次使用迭代器遍历deque中的元素,并输出它们的值;

 💨 可以看到,即使我们在deque中插入了新元素,迭代器仍然可以正确地指向各个元素,这得益于deque迭代器的复合结构和灵活的移动方式。

输出结果如下:

【C++】容器篇(四)—— queue的基本介绍以及模拟实现


 

2、deque的缺陷

与vector比较,deque的优势是:

  • 头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素,因此其效率是比vector高的。

与list比较,deque的优势是:

  • 其底层是连续空间,空间利用率比较高,不需要存储额外字段。

deque有一个致命缺陷:

  • 不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历;
  • 因此在实际中,需要线性结构时,大多数情况下优先考虑vector和list,deque的应用并不多,而目前能看到的一个应用就是,STL用其作 为stack和queue的底层数据结构。

(七)deque作为stack和queue的底层默认容器

1、分析

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

 💨 queue是先进先出的特殊线性数据结构,只要具有 push_back和pop_front操作的线性结构,都可以作为queue的底层容器,比如list。

2、deque的优势

  1. deque提供了在两端进行快速插入和删除的操作,并且支持随机访问。这使得它可以高效地实现栈和队列的基本操作,例如压入元素、弹出元素、获取栈顶或队头元素等等。
  2. 其次,deque的内存分配策略相对于vector更加灵活。vector的内存分配策略是连续的,在需要重新分配内存时,所有的元素都需要被复制到新的内存空间中;而deque的内存分配策略是分块的,每个元素所占用的内存空间是独立的,可以在不影响整个容器的情况下单独分配和回收。

 💨 这样,当需要重新分配内存时,只需要重新分配一部分内存空间,而不需要把所有的元素都复制到新的内存空间中。这使得deque相对于vector具有更好的动态扩展性能和更低的内存开销。

3、原因

STL中对stack和 queue默认选择deque作为其底层容器,主要是因为:

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

因此综上所述,由于deque提供了高效的双端操作和灵活的内存分配策略,使得它成为了实现stack和queue的底层默认容器的理想选择,结合了deque的优点,而完美的避开了其缺陷。


总结

到此,本文的内容便到此结束了,接下来我们简单的回顾一下本文都讲了什么吧!!!

  • 1、首先,我们介绍有关队列的有关知识,知道了其FIFO的特性,并手动实现了一个queue;
  • 2、其次,我们认识了priority_queue,跟学习queue一样,我们知道了在默认情况下队列中的元素是按照大根堆的序列排的;
  • 3、紧接着,我带领大家简单的认识一下关于deque,了解了相关概念以及特性;
  • 4、最后,我们整理了deque作为stack和queue的底层默认容器的具体原因。

以上便是本文的全部内容,希望对大家有所帮助,感谢各位的支持与观看!!!文章来源地址https://www.toymoban.com/news/detail-473064.html

到了这里,关于【C++】容器篇(四)—— queue的基本介绍以及模拟实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • [C++] STL_priority_queue(优先级队列) 的使用及底层的模拟实现,容器适配器,deque的原理介绍

    priority_queue文档介绍 翻译: 1. 优先队列是一种 容器适配器 ,根据严格的弱排序标准, 它的第一个元素总是它所包含的元素中最大的。 2. 此上下文类似于 堆 , 在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。 3. 优先队列被实现为容器适配

    2024年02月04日
    浏览(46)
  • 【C++】容器篇(三)—— stack的基本介绍及其模拟实现

    前言: 在之前的学习中我们已经了解了 vector 和 list ,今天我将带领学习的是关于STL库中的 stack的学习!!! 目录 (一)基本介绍 1、基本概念  2、容器适配器 (二)基本使用 (三)stack模拟实现 1、stack的使用 2、 模拟实现 (四)题目讲解 1、逆波兰表达式求值 (五)总

    2024年02月06日
    浏览(49)
  • 【C++】STL中stack,queue容器适配器的模拟实现(使用deque容器)

    🌏博客主页: 主页 🔖系列专栏: C++ ❤️感谢大家点赞👍收藏⭐评论✍️ 😍期待与大家一起进步! 虽然stack和queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为stack和队列只是对其他容器的接口进行了包装,STL中stack和

    2024年02月15日
    浏览(53)
  • 容器适配器---deque和STL ---stack queue priority_queue的模拟实现 C++

    目录 一、容器适配器 deque原理 deque的缺陷 deque的优势 二、stack的模拟实现  三、queue的模拟实现 四、优先级队列的模拟实现 适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户

    2024年02月02日
    浏览(55)
  • 【C++】STL中的容器适配器 stack queue 和 priority_queue 的模拟实现

    适配器是一种设计模式 (设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。 例如我们常见的充电器就是一种适配器,它将我们常用的220V交流电压转化为4,5V (或者其他更高的电

    2023年04月26日
    浏览(61)
  • [C++]priority_queue的介绍及模拟实现

    目录 priority_queue的介绍及模拟实现::                                                         priority_queue的介绍                                                         priority_queue的定义方式                 

    2024年02月04日
    浏览(44)
  • 【C++】——栈和队列(stack、queue)及优先队列(priority_queue)的介绍和模拟实现

    今天我们来学习C++stl六大组件的其中一种,容器适配器,stack、queue及priority_queue都是容器适配器。我们循序渐进,接下来让我们先认识一下什么是容器适配器。 适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该

    2024年02月08日
    浏览(51)
  • stack 、 queue的语法使用及底层实现以及deque的介绍【C++】

    stack是一种容器适配器,具有后进先出,只能从容器的一端进行元素的插入与提取操作 队列是一种容器适配器,具有先进先出,只能从容器的一端插入元素,另一端提取元素 stack和queue在STL中并没有将其划分在容器的行列,而是称为容器适配器 因为stack和queue对其他容器的接口

    2024年02月12日
    浏览(45)
  • [C++历练之路]vector的介绍以及底层模拟实现

    W...Y的主页 😊 代码仓库分享 💕 🍔前言: 我们学习了STL中的string以及其所有重要接口并进行了模拟实现,但是STL中包含的内容不止于此。学习了string之后继续学习STL中的vector,学习成本会大大降低,因为他们非现类似,现在就让我们进入vector的世界中吧! 目录 vector的介绍

    2024年02月04日
    浏览(47)
  • 【STL】容器适配器stack和queue常见用法及模拟实现

    1.stack介绍及使用 1.1 stack的介绍 stack文档介绍 stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。 stack是作为容器适配器被实现的,容器适配器是使用特定容器类的封装对象作为其基础容器的类,提供一

    2024年02月06日
    浏览(48)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包