单调栈(monotonic stack)的C++实现与应用

本文介绍了单调栈的概念及其C++实现,强调在入栈时保持元素的单调性。通过通用性改进,包括在入栈时的回调处理和提供可定制的比较条件,使得单调栈更具灵活性。单调栈在洛谷P1950等题目中有广泛应用,能够解决寻找特定大小关系的数的问题,常与其他算法结合使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

单调栈(monotonic stack)是一种由栈(stack)衍生出来的数据结构,其操作方式与一般的栈基本一致,只是在元素入栈的时候,需要保证其与原先栈顶元素的大小关系1;若不满足,则不断将栈顶元素弹出,直至关系满足或栈为空为止。以上操作使得栈内的元素具有“单调性”。

但是,由于栈类数据结构通常只能在栈顶位置读写,我们也并不会直接利用容器内元素,而是在新元素入栈时,利用自然产生的信息,即哪些元素被按照规则弹出。也可以在一轮入栈操作后,“观察”栈内剩下的元素,得出一定的结论。

第一个实现

由于C++语言标准在头文件stack中定义了表示一般栈的模板类,可以用它来作为基础。这个数据结构本身逻辑较为简单,不难写出如下单调递增栈的实现(即新入栈的元素必须大于原先栈顶的元素):

// with:
// #include <stack>
// using namespace std;
template <typename T>
class monotonic_stack : public stack<T> 
{
   
public:
	// these three do not change, using them to simplify
	using stack<T>::empty;
	using stack<T>::top;
	using stack<T>::pop;
	
	void push(T val)
	{
   
		while (!empty() && val <= top())
		{
   
			pop();
		}
		stack<T>::push(std::move(val)); // call push of base class
	}
};

通用性改进

入栈时的额外操作

在简介中提到,这种数据结构的用途往往在于其push操作中自然形成的结构。如果像上面的代码那样封装,那这一信息对外界是缺失的,就无法发挥这个数据结构真正的作用。弥补这一缺陷的方式有很多,例如可以把被自动弹出的元素整体返回,或者利用回调函数直接在发生自动弹出的时刻对这样的情况进行处理。整体返回往往要较多考虑内存管理和性能的问题,因此这里给出一个用模板参数封装回调的实现:

// with:
// #include <stack>
// using namespace std;
template <typename T, typename callback>
class monotonic_stack : public stack<T> 
{
   
private:
	callback _cb;
public:
	// these three do not change, using them to simplify
	using stack<T>::empty;
	using stack<T>::top;
	using stack<T>::pop;
	
	void push(T val)
	{
   
		while (!empty() && val <= top())
		{
   
			_cb(top(
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值