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;
	};
}
相关推荐
驭渊的小故事20 分钟前
Spring AI Alibaba 实战:从maven依赖治理到声明式工具调用
java·人工智能·spring
Elastic 中国社区官方博客44 分钟前
我们如何通过 70 多个拉取请求,将 OpenTelemetry Java agent 迁移到 invokedynamic
java·大数据·开发语言·elasticsearch·搜索引擎·全文检索·es
tyn1881 小时前
记录本地安装nacos服务的方法及异常
java·开发语言
步行cgn2 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
y1su2 小时前
Leetcode 字符串模板
java·数据结构·算法·leetcode·职场和发展·动态规划
Elcker2 小时前
YnuoAgent(依诺):一个 npm 包,跑起属于自己的 AI 研发平台
前端·人工智能·npm
计算机魔术师2 小时前
发现2天,修复2个月:AI挖穿PHP后,卡兹克讲透攻防时间差
前端
风骏时光牛马3 小时前
测试标题001
前端
syagain_zsx3 小时前
BRpc 二次封装:Channel 管理、服务管理与回调工厂
c++·学习·程序人生·rpc·谷歌
我命由我123453 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法