C++ stack和queue

༺ 个人主页 · 纪念229 ༻

🏠我的博客主页🏠

༒专栏目录:《数据结构》༒

༒专栏目录:《算法》༒

༒专栏目录:《C++》༒

༒专栏目录:《MySQL数据库》༒

༒专栏目录:《前端开发》༒

༒其它有趣的计算机知识༒

༺世上本没有路,走的人多了自然就有了༻


本篇文章讲述的是C++ stack和queue模版的代码讲解,希望对你有所帮助


文章目录


由于是模板我先展示完全代码在一个个讲解、

1.stack.h

这里我讲解stack的时候会涉及queue其实差不多就是成员函数有一点区别

c 复制代码
#pragma once
//栈逻辑不挑容器(栈的成员变量是容器)只要可以在back push pop就可以容器可以是list,vector,deque
//容器(list,vector,deque等)
//我们要用适配器(成员变量里要有容器就要在文件里写上对应的头文件)适配器写在模板内
#include<vector>
#include<list>
#include<deque>
namespace zjz
{
	//适配器/配接器
	//容器适配器(就是某个类的成员变量是个容器)
	template<class T, class Container = deque<T>>//deque头文件是#include<deque>要在std域里使用因为该头文件会放到有using namesapce std的域里面用所以没问题
	//deque是list和vector的结合体但功能不全back也可以push和pop
	//这里的模板是模板参数加默认实参模板参数可以是大多数类型这里的默认实参要的stack所需要的容器
	class stack//栈模板有两个参数一个写类型一个写容器不写容器就默认是deque容器在实例化的时候<XX,XX>
	{
		//因为成员变量是容器它的默认构造和拷贝构造函数(可以深拷贝)不用设计没问题()只要设计普通成员函数即可
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}

		void pop()
		{
			_con.pop_back();
		}

		size_t size()const
			//size_t size()这里要加const
		{
			return _con.size();
		}

		bool empty()const
			//bool empty()这里要加const
		{
		  return _con.empty();
			//_con.empty();返回类型为bool所以要返回
		}

		const T& top()const
			//const T& top()这里返回top(最后一个元素)意思是const对象返回的元素是const类型非const对象返回类型是非const元素
		{
			return _con.back();//list vector deque 里的back函数就是返回目标变量里的最后一个元素
		}
		T& top()
		{
			return _con.back();
			//_con.back();有返回类型要return
		}
	private:
		Container _con;//栈的成员变量就是容器
	};
}

stack模板中加了个适配器(用在成员变量中的容器),有了适配器所以我们要在.h文件中加上有关容器的头文件比如用list容器我们要加头文件 list

容器就是STL里面的一些模板(list、vector、deque等)

stack模板由模板参数和默认实参(适配器)构成

template<class T, class Container = deque<T>>

默认实参上我们用了缺省参数 用了个容器 deque

deque容器有stack和queue的大多数功能就是没有它们更精细排序效率低

stack和queue模板都有适配器它们的成员变量都是容器

c 复制代码
private:
Container _con;

在stack模板中

这里Container容器可以是list、vector、deque

stack容器没什么要求只需要back可以push pop

stack和list因为成员变量只有容器所以构造函数不用写因为STL容器自身构造函数已设计好所以我们主要实现stack和queue的成员函数(其它没区别)

c 复制代码
void push(const T& x)
{
	_con.push_back(x);
}

stack里面的push入栈直接将匹配好的容器对象push_pack即可

c 复制代码
void pop()
{
	_con.pop_back();
}

pop函数出栈让容器对象pop_back即可

c 复制代码
size_t size()const
	//size_t size()这里要加const
{
	return _con.size();
}

这里直接返回容器对象调用size即可size函数返回的是size_t的数据,size函数的意思是stack中有多少有效数据

这里强调函数后加const是因为该函数并不修改成员变量内容所以用const

c 复制代码
bool empty()const
{
	return _con.empty();
}

这里empty函数直接返回容器对象函数empty即可为空即为true不为空即为false,这里是判断stack是否为空

c 复制代码
const T& top()const
	//const T& top()这里返回top(最后一个元素)意思是const对象返回的元素是const类型非const对象返回类型是非const元素
{
	return _con.back();//list vector deque 里的back函数就是返回目标变量里的最后一个元素
}
T& top()
{
	return _con.back();
	//_con.back();有返回类型要return
}

这里有两个top函数直接返回容器对象(类的成员变量)调用的函数back,这里是返回栈顶元素

一个返回类型没有const而且top()后面没加const意思是·返回的栈顶元素可以修改

一个top函数返回值为const T& top()后接const说明返回取栈顶元素不能被修改

容器list vector deque对象中获取最后一个元素的最好方法是调用back函数


2.queue.h

c 复制代码
#pragma once
//queue类逻辑不挑容器要求front有pop back有push的容器即可(list,deque)
#include<list>
#include<deque>//有适配器就要求有适配容器的头文件
//模板要写在空间域里不然会报错
namespace zjz
{
	//适配器/配接器
	//容器适配器
	template<class T, class Container = deque<T>>
	class queue//queue类的成员变量也是容器
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
			//_con.push_back();最后push_back()的()里要加插入的元素
		}

		void pop()//queue的出(pop)是从头出从尾(back)入
		{
			//_con.erase(_con.begin())这么写会破坏迭代器
			_con.pop_front();
		}

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

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

		const T& front()const//stack只有取栈顶元素top
		{
			return _con.front();
		}

		T& front()
		{
			return _con.front();
		}

		const T& back()const//queue去最后一个元素是back不是top
		{
			return _con.back();
		}

		T& back()
		{
			return _con.back();
		}
	private:
		Container _con;
	};
}

queue这里模板和成员变量就不赘述了

queue容器(list deque)没什么要求只需要front可以top队头出队列back push队尾入队列

c 复制代码
void push(const T& x)
{
	_con.push_back(x);
	//_con.push_back();最后push_back()的()里要加插入的元素
}

这里queue的push是容器对象_con调用push_back队尾入队列

c 复制代码
void pop()//queue的出(pop)是从头出从尾(back)入
{
	//_con.erase(_con.begin())这么写会破坏迭代器
	_con.pop_front();
}

这里容器对象调用pop_front让队头出队列

c 复制代码
size_t size()const
{
	return  _con.size();
}

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

两个差不多这里不赘述了

c 复制代码
const T& front()const//stack只有取栈顶元素top
{
	return _con.front();
}

T& front()
{
	return _con.front();
}

const T& back()const//queue去最后一个元素是back不是top
{
	return _con.back();
}

T& back()
{
	return _con.back();
}

函数front调用容器对象的front函数返回队头元素

返回类型有const 以及front()后有const返回的队头元素无法修改这也是需求

没const的返回的队头元素可以修改

函数back(stack里的返回最后一个元素的函数是top)这里是back返回队尾元素容器对象调用back()即可


3.对deque的认知

deque容器具有stack 和 queue的大多数功能但是排序效率低所以才不常用不然就没有stack和queue了

我们看一下deque对象的排序效率

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
#include<stack>
#include<queue>
#include<algorithm>
#include"stack.h"
#include"queue.h"

//因为在Test.cpp里面用的是std域所以没特别注释域就默认用的就是std里的域类(特别标注的才是其它域的类)

using namespace std;


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

//int main()
//{
//	//zjz::queue<int> q;
//	zjz::queue<int, list<int>> q;//这里<>里面可以写两个一个写类型一个写容器只写一个类型默认容器是deque<T>
//	q.push(1);
//	q.push(2);
//
//	cout << q.front() << " ";
//	q.pop();
//
//	q.push(3);
//	q.push(4);//入队列从队尾入出队列从队头出
//
//	while (!q.empty())
//	{
//		cout << q.front() << " ";
//		q.pop();
//	}
//	cout << endl;
//	return 0;
//}
//void test_op1()
//{
//	srand(time(0));//MSVC编译器中time.h和stdlib.h被头文件iostream所包含
//	const int N = 1000000;
//
//	deque<int> dq;
//	vector<int> v;
//	//利用随机种子循环打印随机值
//	for (int i = 0; i < N; i++)
//	{
//		auto e = rand() + i;
//		v.push_back(e);
//		dq.push_back(e);
//	}
//
//	int begin1 = clock();//clock函数头文件ctime 返回类型是clock_t(通常是long longlong,具体由实现决定)
//	sort(v.begin(), v.end(), less<int>());//sort头文件algorithm  less<T>说明升序排序 greater<T>降序排序第三个参数是个默认对象<>里的类型说明迭代器里的类型是什么
//	int end1 = clock();
//
//	int begin2 = clock();
//	sort(dq.begin(), dq.end());//第三个不写默认是升序排序
//	int end2 = clock();
//
//	printf("vector:%d\n", end1 - begin1);
//	printf("deque:%d\n", end2 - begin2);
//}

void test_op2()
{
	srand(time(0));
	const int N = 100000;

	deque<int> dq1;
	deque<int> dq2;
	for (int i = 0; i < N; i++)
	{
		auto e = rand() + i;
		dq1.push_back(e);
		dq2.push_back(e);
	}

	int begin1 = clock();
	sort(dq1.begin(), dq1.end(), less<int>());
	int end1 = clock();

	int begin2 = clock();
	//vector
	vector<int> v(dq2.begin(), dq2.end());
	sort(v.begin(), v.end());
	dq2.assign(v.begin(), v.end());//assgin就是将迭代器范围(左闭右开)内的数据拷贝到该对象中且迭代器里面的类型与对象目标变量的类型相同且迭代器是输入迭代器
	int end2 = clock();

	printf("deque sort:%d\n", end1 - begin1);
	printf("deque copy vector sort, copy back deque:%d\n", end2 - begin2);
}

int main()
{
	test_op2();

	return 0;
}

//由此可见deque比vector排序慢得多

test_op1我们看一下deque对象排序和vector对象升序排序效率差距

debug

release

test_op2将deque对象排序时间与vector拷贝构造deque然后排序时间

debug

release

举了这些例子就是说明deque没vector效率高所以我们一般会用vector来提效


文章到此就告一段落,希望对你有所帮助,感谢观看!

相关推荐
hhb_6181 小时前
Python异步队列实战:高效处理耗时任务
开发语言·python
weixin_416660071 小时前
Mermaid流程图导出到Word:SVG、PNG与清晰度如何选择?
开发语言·c#
CodeYp20191 小时前
第6讲:模板初阶
开发语言·c++·模板
SEO_juper1 小时前
Node.js 全站死链检测工具:从 sitemap 出发一次找全 404
开发语言·人工智能·python·node.js·seo·外贸独立站
.YM.Z1 小时前
【C++11】初识——右值引用和移动语义,可变参数模板
c++·c++11
喜欢打篮球的普通人1 小时前
LLVM 架构设计与原理:为什么它能取代 GCC 成为新宠
c语言·开发语言
要练八块腹肌2 小时前
红黑树的实现以及对map和set的封装
c++
外收内放2 小时前
FastAPI猜字谜实战(3):把每一局存成JSON
开发语言·python·学习·json·fastapi
tedcloud1232 小时前
Docker Compose 部署 Memos:从安装到备份恢复
linux·开发语言·jvm·后端·docker·容器·rust