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

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

简介

单调栈(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(
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
单调栈和单调队列都是常用的数据结构,用于解决特定的问题。它们的特性可以用来估计时间复杂度。 **单调栈Monotonic Stack)**:单调栈在处理一些需要按特定顺序访问元素的问题时非常有用。如果一个的元素值在遍历过程中保持单调递减或递增(即,对于中的每个元素,其后的元素都小于或大于它),那么这个就被称为单调栈单调栈的时间复杂度通常取决于问题的特性,但通常在最坏情况下是O(n),其中n是问题的规模。这是因为每次访问一个新的元素,都需要将其压入中,这需要O(1)时间,但压入元素后的所有后续操作(例如,弹出元素和查看顶元素)都需要遍历整个,这需要O(n)时间。 **单调队列(Monotonic Queue)**:单调队列通常用于解决需要维护一个单调序列的问题。如果一个队列的元素值在遍历过程中保持单调递增或递减(即,对于队列中的每个元素,它后面的所有元素都小于或大于它),那么这个队列就被称为单调队列。对于单调队列,如果我们遍历一次队列并将结果放入一个新的列表中,那么时间复杂度就是O(n)。这是因为我们需要遍历整个队列来获取结果,而这个过程需要O(n)时间。然而,如果我们使用一个单调栈来维护这个队列,那么时间复杂度就可以降低到O(n log k),其中k是队列中元素的数量。 以上是对这两种数据结构的时间复杂度的基本理解,但请注意,具体的时间复杂度可能会根据问题的具体情况和使用的算法有所不同。在处理实际问题时,最好能够理解问题本身的特点,选择最合适的数据结构算法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值