STL-- C++ stack_queue _priority_queue类 模拟实现

复制代码
最近学习了 STL 中的三种容器适配器,并亲手实现了它们的简化版本。这篇文章记录实现细节、易错点以及核心思想--具体内容可见代码注释部分

一、stack 适配器

基于底层容器实现栈(LIFO)。提供:

  • 构造:可选传入容器对象。

  • empty()、size():判断空、大小(const)。

  • push()、pop():入栈、出栈。

  • top():返回栈顶元素(const 和非 const)。

  • swap():交换两个栈。

cpp 复制代码
namespace JMP1
{
	template <class T,class Container = deque<T>>
	class stack
	{
	public:
		stack(const Container& ctnr = Container())
			:_con(ctnr)
		{

		}
		bool empty() const
		{
			return _con.empty();
		}
		void push(const T& data)
		{
			_con.push_back(data);
		}
		void pop()
		{
			_con.pop_back();
		}
		T& top()
		{
			return _con.back();
		}
		const T& top() const
		{
			return _con.back();
		}
		void swap(stack<T>& x) 
		{
			std::swap(_con, x._con);
		}
		size_t size() const
		{
			return _con.size();
		}
	private:
		Container _con;
	};
	
};

二、queue 适配器

基于底层容器实现队列(FIFO)。提供:

  • 构造:可选传入容器对象。

  • empty()、size():判断空、大小(const)。

  • push()、pop():入队、出队。

  • front()、back():访问队首/队尾元素(const 和非 const)。

  • swap():交换两个队列。

cpp 复制代码
namespace JMP2
{
	template <class T,class Container = deque<T>>
	class queue
	{
	public:
		queue(const Container& ctnr = Container())
			:_con(ctnr)
		{

		}
		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();
		}
		void push(const T& data )
		{
			_con.push_back(data);
		}
		void pop()
		{
			_con.pop_front();
		}
		void swap(queue<T>& x)
		{
			std::swap(_con, x._con);
		}
	private:
		Container _con;
	};
};

三、仿函数(less 和 Greater)

用于自定义比较规则:

  • less<T>:x < y

  • Greater<T>:x > y

    均实现 operator() 为 const。

cpp 复制代码
template<class T>
class less
{
public:
	bool operator()(const T& x,const T& y) const//每次写完成员函数都要考虑 const 是否可以加 应该成为肌肉记忆
	{
		return x < y;
	}
};
template<class T>
class Greater
{
public:
	bool operator()(const T& x,const T& y) const
	{
		return x > y;
	}
};

四、priority_queue 适配器

基于底层容器(默认 vector)和比较器(默认 less)实现二叉堆(默认最大堆)。提供:

  • 构造函数:

    • priority_queue(const Container&, const Compare&):用容器和比较器构造。

    • 模板迭代器构造函数:用 [first, last) 区间构造,并建堆。

  • 容量 :empty()、size()(const)。

  • 访问 :top() 返回堆顶元素(const 和非 const)。

  • 修改:

    • push():插入元素,向上调整。

    • pop():删除堆顶,向下调整。

    • swap():交换两个优先队列。

  • 辅助算法:

    • adjust_up():向上调整(上浮)。

    • adjust_down():向下调整(下沉)。

cpp 复制代码
namespace JMP3
{
	template<class T>
	class less
	{
	public:
		bool operator()(const T& x,const T& y) const//每次写完成员函数都要考虑 const 是否可以加 应该成为肌肉记忆
		{
			return x < y;
		}
	};
	template<class T>
	class Greater
	{
	public:
		bool operator()(const T& x,const T& y) const
		{
			return x > y;
		}
	};
	template<class T, class Container = vector<T>, class Compare = less<T>>//仿函数还没加进去
	class priority_queue//默认优先级是大堆
	{
	public:
		//priority_queue() = default;

		template <class InputIterator>
		priority_queue(InputIterator first, InputIterator last, const Compare& comp = Compare())//实现迭代器构造函数
			:_comp(comp)//初始化列表的这个细节不能忘
		{
			Container v(first, last);
			if (!v.empty())//当size为0时出现 溢出情况 若写的条件类型是size_t就会导致无限循环
			{
				for (int i = (v.size() - 1 - 1) / 2; i >= 0; i--)//其实可以根据传什么参数来 反推前面的代码可能是什么样子
				{
					adjust_down(v, i);
				}
			}
			_con = v;	
		}
		priority_queue( const Container& ctnr = Container(),const Compare & comp = Compare())
			:_con(ctnr)
			,_comp(comp)
		{ }
		bool empty() const
		{
			return _con.empty();
		}

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

		T& top()
		{
			return _con.front();
		}
		const T& top() const
		{
			return _con.front();
		}
		void adjust_up(Container &hp,size_t child)
		{
			size_t parent = (child - 1) / 2;
			while (child>0)
			{
				if (_comp(hp[parent], hp[child]))
				{
					std::swap(hp[child], hp[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
		void push(const T& data)
		{
			_con.push_back(data);
			adjust_up(_con, _con.size()-1);
		}
		void adjust_down(Container& hp, size_t parent)
		{
			size_t child = parent * 2 + 1;
			while (child < hp.size())
			{
				if (child + 1 < hp.size() && _comp(hp[child], hp[child + 1]))	++child;
				if (_comp(hp[parent],hp[child] ))
				{
					std::swap(hp[child], hp[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
		void pop()
		{
			std::swap(_con.front(),_con.back());
			_con.pop_back();
			adjust_down(_con,0);
		}
		void swap(priority_queue<T>& x)
		{
			std::swap(_con, x._con);
		}
	private:
		Container _con;
		Compare _comp;
	};
};

五、常见易错点

  • const 正确性 :不修改对象的成员函数都加了 const。

  • 仿函数支持 :priority_queue 使用 Compare _comp 成员,比较时调用 _comp(a,b)。

  • 默认参数:构造函数提供了默认值。

  • 交换 :swap 成员函数交换底层容器。

我的gitee仓库

https://gitee.com/jiangmingpeng0716/c-learning-process

相关推荐
2601_966949654 小时前
如何根据研究的起止时间截取分钟级行情?Python 实战与 QuantDash 数据处理指南
开发语言·python·pandas·量化交易·1024程序员节·股票数据·quantdash
晨曦中的暮雨6 小时前
限流算法——固定窗口、滑动窗口、漏桶、令牌桶
java·开发语言·算法
喵了几个咪7 小时前
GoWind CMS 拆解:在 Go 里给 TipTap 搭一套 Yjs 协同后端
开发语言·后端·golang
程序员清风7 小时前
数据处理脚本工程化:日志、配置、命令行与测试
服务器·开发语言·数据库
2601_962885729 小时前
如何用 Python 把 K 线重采样成任意周期?
开发语言·python
choumin9 小时前
C++中万能引用与std::forward的作用和用法
c++·万能引用·std forward
Wang's Blog9 小时前
Java 项目实战: 交友项目 - 圈子功能实现:总结
java·开发语言·交友
下一站春风里10 小时前
位运算完整学习笔记:按位与(&)+ 异或(^)
开发语言·c++·算法
天外飞雨道沧桑11 小时前
我在浏览器里练了一个 792 参数的大模型,它学会了补全 JavaScript
开发语言·javascript·ai·ecmascript·ai编程
hhhjhl11 小时前
Yup 跨端三方库仓颉适配全流程
java·开发语言