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;
	};
};

三、仿函数(lessGreater

用于自定义比较规则:

  • 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

相关推荐
半个烧饼不加肉1 小时前
JS 底层探究--上下文
开发语言·javascript·ecmascript
小满Autumn1 小时前
依赖注入设计模式速查手册
开发语言·c#·wpf·mvvm·依赖注入
selt7911 小时前
Redisson 源码深度分析
java·c++·redis·lua
周末也要写八哥1 小时前
浅谈:C++中cpp 14 ~ cpp 17
开发语言·c++·算法
不会C语言的男孩1 小时前
C++ Primer 第13章:拷贝控制
开发语言·c++
z落落1 小时前
C# 静态成员 vs 非静态成员(调用规则+内存特点)+只读和常量 const常量 / readonly / static readonly 三者终极区别
java·开发语言·c#
zhangfeng11331 小时前
超算中心 高性能计算 slurm的linux版本 centos7,如何安装docker,如何安装torch2.4
linux·运维·服务器·开发语言·人工智能·机器学习·docker
c238562 小时前
map和set
数据结构·c++
java1234_小锋2 小时前
LangChain4j 开发Java Agent智能体- 整合SpringBoot4
java·开发语言·langchain4j