C++的stack和Queue

1.简单实现stack

构建一个模板,俩个参数,这里第一个一般是数据的类型,第二个是由什么来实现栈,在主函数里传了int和vector<int>,第二个不传参也可以,因为是缺省参数,默认为vector,这样就可以使用vector封装好的函数使用,push为尾插,就可以使用vector的push_back函数,pop是尾删,top是栈顶的元素,size是栈的大小,最后一个是判断是否为空。

cpp 复制代码
namespace zym
{
	template<class T, class Container = vector<T>>
	class stack
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_back();
		}
		const T& top() const
		{
			return _con.back();
		}
		size_t size() const
		{
			return _con.size();
		}

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

//test.cpp

#include<iostream>
#include<vector>
#include<list>
#include<stack>
#include<queue>
#include<algorithm>
using namespace std;

#include"Stack.h"
#include"Queue.h"
//#include"PriorityQueue.h"


int main()
{
	//bit::stack<int, vector<int>> st;
	//bit::stack<int, list<int>> st;
	zym::stack<int, vector<int>> st;

	// 类模板实例化时,按需实例化,使用哪些成员函数就实例化哪些,不会全实例化
	st.push(1);
	st.push(2);
	st.push(3);
	st.push(4);

	cout << st.top() << endl;
	st.pop();

	zym::queue<int, list<int>> q;
	//zym::queue<int> q;
	//q.push(1);
	//q.push(2);
	//q.push(3);
	//q.push(4);

	//cout << q.front() << endl;
	//q.pop();

	return 0;
}

2.简单实现Queue

跟之前的stack基本是一样的,除了实现原理不一样,队列需要链表,剩下就是使用对应的库函数。

cpp 复制代码
namespace zym
{
	template<class T,class Container=list<int>>
	class queue
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_front();
		}
		const T& front() const
		{
			return _con.front();
		}
		const T& back()
		{
			return _con.back();
		}

		size_t size() const
		{
			return _con.size();
		}
		bool empty() const
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
}



	zym::queue<int> q;
	q.push(1);
	q.push(2);
	q.push(3);
	q.push(4);

	cout << q.front() << endl;
	q.pop();

3.deque

deque概念

deque就是把list和vector合在一起了,把这俩个互补了,vector因为是连续的存储空间,所以尾插和下标访问效率好,且缓存利用率也高,但数组需要扩容,扩容就会带来效率低和空间浪费,在中间位置插入数据效率低,因为要挪动数据。list则是按需申请和释放空间,不需要扩容,链表可以在任意位置插入和删除,缺点是不能像数组一样通过下标访问。而deque是结合俩者的优点,但是效率并不是很好。

deque的底层

链表是一个一个分散的空间,vector则是连续空间,则deque是分散的连续空间,list的每个节点只有一个元素的空间大小,而deque是每个节点变为了一个数组buf,用一个二级指针数字map储存每一个buf的地址,这个map是从中间作为第一个的,如果要头插就会在前面插入。

类里面有四个成员变量,都是迭代器,cur是指向当前元素的下一个,first是当前buf(数组)的第一个,last是最后一个元素的下一个,node是指向储存当前buf的位置。

移动下一个节点

重载的++是先判断cur和last是否一样,如果一样就调用set_node函数,set_node是把node+1赋值给node,first指向node+1的第一个位置,last等于first+这个数组的大小。

下标访问

如果是在第一个buf,要访问第n个,则可以先找到是在哪一个buf,n/sizeof(buf)表示是在第几个buf,然后是去找是在buf里面的第几个位置,n%sizeof(buf)表示是在buf里面的第几个位置,如果是在前面(头插后),则这样的办法就不太行,需要另外的,vs的编译器是把下标n和cur-first相加。

头插

注意的是头插的话,是从last位置开始的,这时候last就是最后一个元素的下一个,cur就是指向当前元素而不是下一个了。

插入和删除

如果在中间要插入和删除,都会挪动数据,就会有效率低的问题,如果是让buf的容量加减在插入和删除时,这样又会有问题,每个buf的大小不一样,在下标访问就需要更复杂的计算了,vs则是buf不变。

总结

1.deque头插尾插效率高

2.下标访问也还不错(计算以及判断多有影响)

3.中间插入删除效率很低,要挪动数据

4.用deque来实现stack和queue

注意:对于模板在没有按需实例化时,不会检查细节的代码,只会检查大概,所以可能运行没问题,后面有问题是因为有写函数没有调用,调用了编译器才会仔细检查代码的合理性。

queue:

cpp 复制代码
namespace zym
{
	template<class T,class Container=deque<int>>
	class queue
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_front();
		}
		const T& front() const
		{
			return _con.front();
		}
		const T& back()
		{
			return _con.back();
		}

		size_t size() const
		{
			return _con.size();
		}
		bool empty() const
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
}

stack:

cpp 复制代码
namespace zym
{
	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() const
		{
			return _con.back();
		}
		size_t size() const
		{
			return _con.size();
		}

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

5.priority_queue

priority_queue跟堆很像,堆是用来实现优先级队列的,所以底层还是堆的实现那些。

仿函数

这里的类Less和Greater里面只有一个成员函数,没有成员变量,但我们要建大堆和小堆时需要改变代码的大于号或者小于号,是不方便的,所以可以在priority_queue模板再加一个参数,来接受仿函数,需要小于就传Less,需要大于就传Greater,这样就可以一个代码实现大堆和小堆。

cpp 复制代码
template<class T>
class Less
{
public:
	bool operator()(const T& x, const T& y)
	{
		return x < y;
	}
};
template<class T>
class Greater
{
public:
	bool operator()(const T& x, const T& y)
	{
		return x > y;
	}
};

实现代码:

cpp 复制代码
#pragma once

#include<vector>

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

namespace zym
{
	template<class T, class Container = vector<T>, class Compare = Less<T>>
	class priority_queue
	{
	public:
		void AdjustUp(int child)
		{
			Compare com;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				if (com(_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)
		{
			size_t child = parent * 2 + 1;
			Compare com;
			while (child < _con.size())
			{
				if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
				{
					++child;
				}
				if (com(_con[parent], _con[child]))
				{
					swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
					break;
			}
				
		}
		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			AdjustDown(0);
		}
		const T& top()
		{
			return _con[0];
		}

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

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

		
	private:
		Container _con;
	};
}
相关推荐
「QT(C++)开发工程师」4 分钟前
C++11三大核心特性深度解析:类型特征、时间库与原子操作
java·c++·算法
乐分启航10 分钟前
SliMamba:十余K参数量刷新SOTA!高光谱分类的“降维打击“来了
java·人工智能·深度学习·算法·机器学习·分类·数据挖掘
网络点点滴22 分钟前
组件通信-作用域插槽
前端·javascript·vue.js
yoothey1 小时前
Java字节流与字符流核心笔记(问答+考点复盘)
java·开发语言·笔记
kyriewen111 小时前
异步编程:从“回调地狱”到“async/await”的救赎之路
开发语言·前端·javascript·chrome·typescript·ecmascript·html5
Old Uncle Tom1 小时前
Markdown Viewer 再升级
前端
Luna-player1 小时前
Vue3中使用vue-awesome-swiper
前端·vue.js·arcgis
SuperEugene1 小时前
Vue3 Pinia 状态管理规范:状态拆分、Actions 写法、持久化实战,避坑状态污染|状态管理与路由规范篇
前端·javascript·vue.js·前端框架·pinia
black方块cxy1 小时前
实现一个输入框多个ip以逗号分隔最多20组,且ip不能重复
java·服务器·前端
Jordannnnnnnn2 小时前
追赶33名
c++