C++ | stack与queue

目录

前言

一、C++中的栈

1、适配器容器

2、栈的使用

3、栈的模拟实现

二、C++的队列

1、队列的使用

2、队列的模拟实现

三、deque


前言

        本文主要讲解在C++中栈与队列的使用以及模拟实现, 关于栈和队列相关概念,我们早就在数据结构中的栈与队列介绍过,本文就不再复述,如果还不了解可以点击下方链接,先去看看关于栈与队列的基本概念;

栈与队列(C语言版)

一、C++中的栈

1、适配器容器

        在C++中,栈实际上时一种适配器容器,什么叫适配器容器呢?适配器容器实际上是对一般序列容器的封装,使其具有某种特殊功能,实际上,我们接下来会学习的queue与priority_queue都是适配器容器;

        这里有一个关于模板知识的补充,实际上,模板的类型还可以是容器,我们可以给模板参数缺省值,并且,给缺省值的规则与我们给函数缺省值的规则一致; 函数缺省复习入口

这里我们发现给的缺省值是deque,deque也是一种容器,也叫双端队列,关于双端队列,后面会详细介绍;

2、栈的使用

关于栈的使用,一共有如下接口,均查阅于文档;文档链接

        如果学习过我们之前C语言版的栈,相信大部分接口大家看一眼大概都会使用;我们用C语言模拟实现的栈的接口命名也来自STL中的stack;下面我们粗略的通过代码来学习这些接口的使用;(emplace暂可不用了解)

void test_stack()
{
	// 第二个模板参数默认会使用双端队列
	stack<int> st1;
	// 指定使用vector适配容器
	stack<int, vector<int>> st2;
	// 插入数据
	st1.push(1);
	st1.push(2);
	st1.push(3);
	st1.push(4);
	st1.push(5);
	// 判空
	while (!st1.empty())
	{
		// 取栈顶数据
		cout << st1.top() << " ";
		// 出栈
		st1.pop();
	}
	cout << endl;
}

3、栈的模拟实现

        栈的模拟实现也很简单,有了之前学习C语言版本栈的模拟实现的基础,这里的实现就更简单了;

#include <deque>

namespace MySpace
{
	template<class T, class Container = std::deque<T>>
	class stack
	{
	public:
		void push(const T& val)
		{
			_con.push_back(val);
		}
		void pop()
		{
			_con.pop_back();
		}
		bool empty() const
		{
			return _con.empty();
		}
		size_t size() const
		{
			return _con.size();
		}
		T& top()
		{
			return _con.back();
		}
		const T& top() const
		{
			return _con.back();
		}
	private:
		Container _con;
	};
}

        主要的思想还是复用模板容器的接口,这里仅仅只需大概40就可以模拟实现出一个stack;真的真的不要太简单;这里可以充分体会到了C++模板的魅力!(我为模板举大旗)

二、C++的队列

1、队列的使用

        同样,队列也是适配器容器;与stack一样;连模板参数也是一模一样,这里就不做过多的介绍; 

        queue主要有以下接口;大部分接口大家也在之前介绍栈与队列那篇文章有做介绍;

void test_queue()
{
	// 第二个容器模板参数使用默认的deque
	queue<int> q1;
	// 第二个模板参数使用list
	queue<int, list<int>> q2;
	// 队尾插入数据
	q1.push(1);
	q1.push(2);
	q1.push(3);
	q1.push(4);
	q1.push(5);
	// 判空
	while (!q1.empty())
	{
		cout << "队头: " << q1.front() << "队尾: " << q1.back() << endl;
		// 队头出数据
		q1.pop();
	}
	cout << endl;
}

2、队列的模拟实现

        队列的模拟实现同样也很简单;代码如下;

#include <deque>

namespace MySpace
{
	template<class T, class Container = std::deque<T>>
	class queue
	{
	public:
		void push(const T& val)
		{
			_con.push_back(val);
		}
		void pop()
		{
			_con.pop_front();
		}
		bool empty() const
		{
			return _con.empty();
		}
		size_t size() const
		{
			return _con.size();
		}
		T& front()
		{
			return _con.front();
		}
		const T& front() const
		{
			return _con.front();
		}
		T& back()
		{
			return _con.back();
		}
		const T& back() const
		{
			return _con.back();
		}

	private:
		Container _con;
	};
}

        关于栈与队列这一部分的实现对于我们来说几乎没有什么难度,对于栈与队列,实际上主要难点在于这两个容器在OJ题中的使用;我们可以通过以下这几个OJ题来加强我们对这两个容器的理解;

用栈实现队列

用队列实现栈

最小栈

栈的压入、弹出序列

逆波兰表达式求值

三、deque

        deque是双端队列,我们可以在队头与队尾入数据与出数据,实际上,它是vector与list的结合;

        如上图结构,deque实际上有一个中控数组,其中储存的都是数组指针,指向一个数组,每个数组都可以储存一定的数据(SGI实现版本);我们当我们需要头插时,我们直接在中控中,创建一个数组指针,接着往其中buf缓冲区写入数据,尾插也类似;由于每个缓冲区大小差不多,因此我们可通过计算实现类似数组的随机访问;

总结:

        实际上,deque的使用并不多,既然deque又有vector的优点,也有list的优点,那为什么用的不多呢?实际上,deque有以下优缺点;

优点:

  1. 可随机访问
  2. 可头插尾插,且效率不低
  3. 扩容代价低

缺点:

  1. 中间的插入删除效率低
  2. 不适合遍历,因为遍历时,频繁检测是否要进入下一个buf区间

        最后,之所以使用deque作为stack与queue的默认适配容器,是因为我们在使用stack与queue的时候一般没有遍历的需求,也没有中间位置插入的需求,deque还可头尾插删,效率也不低,因此选择deque作为默认的适配容器;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值