栈的常用操作
- 进栈 - push - 将元素放置到栈顶
- 退栈 - pop - 将栈顶元素弹出
- 栈顶 - top - 得到栈顶元素的值
- 是否空栈 - isEmpty - 判断栈内是否有元素
应用
- 函数调用栈
- 浏览器前进后退
- 匹配括号
- 单调栈用来寻找下一个更大(更小)元素
单调栈又是什么?
单调栈是一种特殊的栈。栈本来就是一种受限的数据结构了,单调栈在此基础上又受限了一次(受限++)。
单调栈要求栈中的元素是单调递减或者单调递减的。
是否严格递减或递减可以根据实际情况来。
这里我用 [a,b,c] 表示一个栈。 其中 左侧为栈底,右侧为栈顶。单调增还是单调减取决于出栈顺序。如果出栈的元素是单调增的,那就是单调递增栈,如果出栈的元素是单调减的,那就是单调递减栈。
比如:
- [1,2,3,4] 就是一个单调递减栈(因为此时的出栈顺序是 4,3,2,1。下同,不再赘述)
- [3,2,1] 就是一个单调递增栈
- [1,3,2] 就不是一个合法的单调栈
那这个限制有什么用呢?这个限制(特性)能够解决什么用的问题呢?
适用场景
单调栈适合的题目是求解下一个大于 xxx或者下一个小于 xxx这种题目。所有当你有这种需求的时候,就应该想到单调栈。
那么为什么单调栈适合求解下一个大于 xxx或者下一个小于 xxx这种题目?原因很简单,我这里通过一个例子给大家讲解一下。
这里举的例子是单调递减栈
比如我们需要依次将数组 [1,3,4,5,2,9,6] 压入单调栈。
- 首先压入 1,此时的栈为:[1]
- 继续压入 3,此时的栈为:[1,3]
- 继续压入 4,此时的栈为:[1,3,4]
- 继续压入 5,此时的栈为:[1,3,4,5]
- 如果继续压入 2,此时的栈为:[1,3,4,5,2] 不满足单调递减栈的特性, 因此需要调整。如何调整?由于栈只有 pop 操作,因此我们只好不断 pop,直到满足单调递减为止。
- 上面其实我们并没有压入 2,而是先 pop,pop 到压入 2 依然可以保持单调递减再 压入 2,此时的栈为:[1,2]
- 继续压入 9,此时的栈为:[1,2,9]
- 如果继续压入 6,则不满足单调递减栈的特性, 我们故技重施,不断 pop,直到满足单调递减为止。此时的栈为:[1,2,6]
栈的实现
栈是较容易实现的抽象数据结构之一。我们可以选择数组或者链表来实现,它们各有特点,前者容量有限且固定,但操作简单,而后者容量理论上不受限,但是操作并不如数组方便,每次入栈要进行内存申请,出栈要释放内存,稍有不慎便造成内存泄露。本文对两种实现都做介绍。
数组实现栈
用数组实现栈是比较容易的。这个时候的栈其实更像是访问受限的数组,数组可以通过下标访问,查找,插入等,但是栈只能从栈顶,或者说数组的末尾进行操作。我们只需要一个指针记录栈顶即可。有人可能问了,既然这里栈是访问受限的数组,为什么不直接使用数组呢?所谓能力越大,责任越大,而你暴露的越多,风险也越大就是如此。
c语言实现
#include<stdio.h> #define STACK_SIZE 64 /*栈大小*/ #define TOP_OF_STACK -1 /*栈顶位置*/ typedef int ElementType; /*栈元素类型*/ #define SUCCESS 0 #define FAILURE -1 /*定义栈结构*/ typedef struct StackInfo { int topOfStack; /*记录栈顶位置*/ ElementType stack[STACK_SIZE]; /*栈数组,也可以使用动态数组实现*/ }StackInfo_st; /*函数声明*/ int stack_push(StackInfo_st *s,ElementType value); int stack_pop(StackInfo_st *s,ElementType *value); int stack_top(StackInfo_st *s,ElementType *value); int stack_is_full(StackInfo_st *s); int stack_is_empty(StackInfo_st *s); /*入栈,0表示成,非0表示出错*/ int stack_push(StackInfo_st *s,ElementType value) { if(stack_is_full(s)) return FAILURE; /*先增加topOfStack,再赋值*/ s->topOfStack++; s->stack[s->topOfStack] = value; return SUCCESS; } /*出栈*/ int stack_pop(StackInfo_st *s,ElementType *value) { /*首先判断栈是否为空*/ if(stack_is_empty(s)) return FAILURE; *value = s->stack[s->topOfStack]; s->topOfStack--; return SUCCESS; } /*访问栈顶元素*/ int stack_top(StackInfo_st *s,ElementType *value) { /*首先判断栈是否为空*/ if(stack_is_empty(s)) return FAILURE; *value = s->stack[s->topOfStack]; return SUCCESS; } /*判断栈是否已满,满返回1,未满返回0*/ int stack_is_full(StackInfo_st *s) { return s->topOfStack == STACK_SIZE - 1; } /*判断栈是否为空,空返回1,非空返回0*/ int stack_is_empty(StackInfo_st *s) { return s->topOfStack == - 1; } int main(void) { /*创建栈*/ StackInfo_st stack; stack.topOfStack = TOP_OF_STACK; /*如果栈为空,则压入元素1*/ if(stack_is_empty(&stack)) { printf("push value 1\n"); stack_push(&stack,1); } /*访问栈顶元素*/ int topVal; stack_top(&stack, &topVal); printf("top value %d\n",topVal); /*出栈*/ int popVal; stack_pop(&stack, &popVal); printf("pop value %d\n",popVal); int i = 0; while(SUCCESS == stack_push(&stack,i)) { i++; } printf("stack is full,topOfStack is %d\n",stack.topOfStack); return 0; }
例题:每日温度
请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。
如果气温在这之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],
你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
通过次数175,107提交次数260,236
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/daily-temperatures
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
#include<string.h>
#define STACK_TOP_IDX -1
struct stack_st
{
int stackTop;
int stackData[30000];
};
int Top(struct stack_st *stackData, int *value)
{
if (stackData->stackTop == STACK_TOP_IDX)
{
return 0;
}
*value = stackData->stackData[stackData->stackTop];
return 1;
}
void pop(struct stack_st *stackData)
{
if (stackData->stackTop == STACK_TOP_IDX)
{
return ;
}
stackData->stackTop--;
return ;
}
void push(struct stack_st *stackData, int data)
{
if (stackData->stackTop == 29999)
{
return ;
}
stackData->stackTop++;
stackData->stackData[stackData->stackTop] = data;
return ;
}
int* dailyTemperatures(int* temperatures, int temperaturesSize, int* returnSize){
int ret = 0, mid = 0, i = 0;
int *temp = (int *)calloc(temperaturesSize, sizeof(int));
if (temperaturesSize <= 1)
{
*returnSize = 1;
printf("0\n");
temp[0] = 0;
return temp;
}
struct stack_st myStack;
memset(&myStack, 0, sizeof(struct stack_st));
myStack.stackTop = STACK_TOP_IDX;
push(&myStack, 0);
for (i = 0; i < temperaturesSize - 1; i++)
{
if (temperatures[i+1] <= temperatures[i])
{
push(&myStack, i+1);
}
else
{
while(1)
{
if (!Top(&myStack, &mid))
break;
if (temperatures[mid] < temperatures[i+1])
{
temp[mid] = i+1;
pop(&myStack);
}
else
{
break;
}
}
push(&myStack, i+1);
}
}
for (i = 0; i < temperaturesSize ; i++)
{
temp[i] = temp[i] - i;
if (temp[i] < 0)
temp[i] = 0;
if (i == temperaturesSize - 1)
printf("%d\n", temp[i]);
else
printf("%d, ", temp[i]);
}
*returnSize = temperaturesSize;
return temp;
}