一,栈的诠释
栈是一种常见的数据结构,我们使用栈这个操作来完成一些基础的线性的操作,我们要深刻的理解栈这种操作,以及他所适应的场景本文依照模拟栈的思路来讲解,模拟栈分为两大板块,指针,存储空间q[N] ,通常情况下,我们在使用一个指针就能完成绝大多数的基本操作,下图是一个常见的栈的结构。
模拟栈的基本操作包括,入栈操作,出栈操作,判断栈顶是否为空操作,返回栈顶操作;
入栈操作: 移动指针,赋值
出栈操作:移动指针,类似于计算机中的删除操作
特性操作:是否为空,返回栈顶
单调栈 的使用方法,单调栈我们经常使用于和 单调队列 一样的操作中,当然单调栈 的数据中一般不会进行出队操作,所以我们使用起来可能会更加简单,队列中存储的是洗标,栈中不仅可以存储下标,我们也可以存储值,当然我们在队列中开一个nq[N]数组也能存储这些值 ,我们在学习单调栈之后可以把单调栈的思想带入单调队列,从而完成数据的存储
二,模拟栈的实现
模拟栈的操作有: 栈的创建,出栈,入栈, 判断栈是否为空,返回栈顶
1, 栈的创建
const int N = 100010 ;
int stk[N], tt = - 1 ;
//stk为存储空间,存储函数值,和单调栈存储下标不同;
2.向栈中压入元素
void push (int u)
{
stk[++ tt] = u ;
}
//入栈操作 , 把函数值压入栈中
3.从栈中弹出元素
void pop ()
{
tt -- ;
}
4,返回栈空否
void empty()
{
return tt == - 1 ;
}
5,返回栈顶元素
int top ()
{
return stk[tt] ;
}
模拟栈的总函数
#include <iostream>
using namespace std ;
const int N = 100010 ;
int stk[N], tt = - 1 ;
//stk为存储空间,存储函数值,和单调栈存储下标不同;
void push (int u)
{
stk[++ tt] = u ;
}
//入栈操作 , 把函数值压入栈中
void pop ()
{
tt -- ;
}
void empty()
{
return tt == - 1 ;
}
int top ()
{
return stk[tt] ;
}
int main ()
{
return 0 ;
}
在我们还没有学习stl的情况下我们可以使用这个模拟栈的操作来代替栈的操作。
三,单调栈
1,题型模板
单调栈题型,一般情况下是和他的距离最近且满足大小关系的数值进行操作,我们看到临近问题第一点应该就想到单调栈操作,并且这种最近的问题一般还是单方向的,无方向问题有时候也能使用单调栈进行模拟出来。
2,算法模板
#include <iostream>
using namespace std ;
const int N = 100010 ;
int stk[N] , tt = -1 ;
int main ()
{
int n ;
cin >> n ;
for(int i = 0 ; i < n ; i ++ )
{
int x ;
cin >> x ;
while (tt != - 1 && stk[tt] >= x ) tt -- ;
//1.指定顺序关系弹出栈顶元素&&保证栈内有元素————保证栈的单调性
if(tt == -1 ) cout << tt <<" ";
else cout << stk[tt] << " " ;
stk[++ tt] = x ;
}
cout << endl;
return 0 ;
}
3,算法思想
总的来说,无论是单调栈还是单调队列,他们两种数据结构都是一种优化的思想,减少遍历操作从而完成对整个算法的优化操作,从而减少遍历次数的算法,虽然说这个就是算法本质的思想,但是这个思想在这两个数据结构中表现得更加明显,这两个操作是根据特性来实现操作的比较简单的算法,比较依托题目,以前学习的二分,排序,高精度…都有完整的模板并且都有明确思路,这个数据结构是通过自身的特性来实现算法操作,比如单调栈就是使用题目的单调性,我们不仅能像堆一样使用自身的最小值特性,也能和题目结合使用题目的特性。