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;
	};
}
相关推荐
XiaoLeisj3 分钟前
【MyBatis】深入解析 MyBatis XML 开发:增删改查操作和方法命名规范、@Param 重命名参数、XML 返回自增主键方法
xml·java·数据库·spring boot·sql·intellij-idea·mybatis
风象南3 分钟前
SpringBoot实现数据库读写分离的3种方案
java·spring boot·后端
奇怪的知识又增长了8 分钟前
Command SwiftCompile failed with a nonzero exit code Command SwiftGeneratePch em
前端
Maofu8 分钟前
从React项目 迁移到 Solid项目的踩坑记录
前端
薄荷味8 分钟前
ubuntu 服务器安装 docker
前端
Carlos_sam9 分钟前
OpenLayers:如何控制Overlay的层级?
前端·javascript
阳光_你好9 分钟前
请详细说明opencv/c++对图片缩放
c++·opencv·计算机视觉
振鹏Dong10 分钟前
策略模式——本质是通过Context类来作为中心控制单元,对不同的策略进行调度分配。
java·策略模式
莫循瑾木13 分钟前
Vue3 Composition API 完全指南
前端·vue.js·前端工程化
初辰ge15 分钟前
后端说“基本增删改查都写好了,就差切图仔对接口了!”——我一怒之下撸了个代码生成器
前端·vue.js