最小栈
最小栈(Min Stack)是一个支持常数时间复杂度获取栈中最小元素的特殊栈数据结构。通常,标准的栈数据结构只支持在常数时间内执行入栈(push)和出栈(pop)操作,但无法在常数时间内获取栈中的最小元素。
最小栈通过在每个栈节点中额外存储一个当前阶段的最小值,从而实现在常数时间内获取最小元素的功能。这意味着无论栈的大小如何,都可以在常数时间内获取栈中的最小值。
最小栈的主要操作包括:
-
入栈(push):将元素压入栈顶,并更新当前最小值。
-
出栈(pop):从栈顶弹出一个元素。
-
获取最小值(getMin):返回栈中的最小元素,即栈顶节点的最小值。
这样,在使用最小栈时,我们可以通过调用 getMin
操作来获取栈中的最小元素,并保持常数时间复杂度。其他与标准栈一致的操作,例如入栈和出栈,仍然可以在常数时间内执行。
使用最小栈的一个常见场景是需要快速获取栈中的最小元素的问题,例如实现一个获取最小元素的栈(MinStack)或解决一些需要以常数时间获取最小值的算法问题。
栈结构
代码实现
#include <iostream>
#ifndef TEST_MIN_STACK_H
#define TEST_MIN_STACK_H
using namespace std;
class StackNode{
public:
int val;
StackNode * next;
StackNode(int v):val(v),next(nullptr){}
};
class MinStack {
public:
MinStack() {
}
void push(int val) {
// 将元素压入栈
StackNode* n;
data == nullptr ? (data = new StackNode(val)) && nullptr : (n = new StackNode(val)) && (n->next = data) && (data = n);
// 更新最小值栈
if (minData == nullptr) {
minData = new StackNode(val);
}else if(val <= minData->val){
StackNode* n = new StackNode(val);
n->next = minData;
minData = n;
}
}
void pop() {
if (data != nullptr) {
// 取出栈顶元素
int top = data->val;
// 如果栈顶元素是最小值,同时从最小值栈中弹出
if (minData != nullptr && top == minData->val) {
StackNode* t = minData;
minData = minData->next;
delete t;
}
// 弹出栈顶元素
StackNode* t = data;
data = data->next;
delete t;
}
}
int top() {
// if (data != nullptr) {
// // 返回栈顶元素
// return data->val;
// }
// // 当栈为空时,返回一个无意义的值
// return INT_MIN;
return data == nullptr ? INT_MIN : data->val;
}
int getMin() {
//if (minData != nullptr) {
// 返回最小值栈的栈顶元素
// return minData->val;
// }
// 当栈为空时,返回一个无意义的值
// return INT_MIN;
return minData == nullptr ? INT_MIN : minData->val;
}
private:
StackNode *data = nullptr;
StackNode *minData = nullptr;
};
#endif //TEST_MIN_STACK_H
实现分析
MinStack
类中有两个私有成员变量 data
和 minData
,分别表示存储栈元素的栈和存储最小值的栈。这两个栈都是通过 StackNode
类的节点构成的。
下面是对 MinStack
类的各个方法进行分析:
-
void push(int val)
:将元素压入栈。该方法首先判断data
是否为空,如果为空,则创建一个新的节点作为栈顶,并将data
指向该节点;如果不为空,创建一个新节点并将其指向当前的栈顶节点,然后将data
指向新的节点。接着,该方法更新最小值栈minData
。如果minData
为空,直接创建一个新节点作为最小值栈的栈顶;如果不为空,并且当前值小于等于最小值栈的栈顶元素,创建一个新节点,并将其指向最小值栈的栈顶节点,然后将minData
指向新的节点。-
图解:
-
StackNode* n = new StackNode(val);
-
n->next = data;
-
data = n;
-
-
-
void pop()
:弹出栈顶元素。首先判断data
是否为空,如果为空则直接返回。如果data
不为空,则取出栈顶元素top
。如果minData
不为空且栈顶元素top
等于最小值栈的栈顶元素,则将最小值栈的栈顶元素弹出。接着,将栈顶元素弹出,并释放内存。 -
int top()
:返回栈顶元素的值。如果data
为空,返回INT_MIN
,否则返回栈顶节点的值。 -
int getMin()
:返回最小值栈的栈顶元素的值。如果minData
为空,返回INT_MIN
,否则返回最小值栈的栈顶节点的值。
总体而言,该代码实现了一个基本的最小栈,支持在常数时间内进行入栈、出栈、获取栈顶元素和获取最小值的操作。
其他实现方式
使用stack,vector或deque实现MinStack。把其中的data和minData属性换成对应的容器对象即可。