上一篇详解了二叉树转双向链表,此篇作为【C语言强化】系列第二篇,来聊聊有关栈的一道题,
通过这道题,你可以掌握
- 如何使用栈“先进后出"的特性
- 如何巧妙地借助辅助栈
- 如何在结构体中定义可共享的静态成员变量
题目
看似很简单的求最小值函数,思路有很多很多。笔者首先想到每次push入栈都进行一次排序,使这个栈的栈顶永远是最小元素,然后就发现这是一个很蠢很蠢的想法,第一这样做会改变了栈的结构,第二不满足题目对时间复杂度的要求。
愚蠢归愚蠢,还是有点用的。既然不能改变原来栈的结构,那为何不弄俩栈呢?辅助栈的想法由此而出。
接下来是时间复杂度的问题,显然每次都进行排序是不可行的了,那么是否可以记录保存每个最小值的下一个最小值呢,也就是说,当我当前这个最小值被pop出去后,我要知道下一个最小值是哪个。这时栈的【先进后出】特性就派上用场了。
头脑风暴到此结束。下面是具体思路
牢牢把握住栈【先进后出】的特性,模拟各种实际情况,得出算法
辅助栈:
栈结构体中添加一个辅助栈,这里称为【最小值栈】,存储最小值的历史记录,所以该最小值栈的栈顶即为当前栈的最小元素
算法实现:
--push
当push进来的元素值大于、等于最小值栈的栈顶,最小值栈不变,因为根据栈的特性,只有当前最小值元素上面的所有元素都出去的时候,该最小值元素才能pop出去,否则该最小值元素用于是最小值。
反之,当push进来的元素值小于最小值栈的栈顶,则将该元素放进最小值栈。
反之,当push进来的元素值小于最小值栈的栈顶,则将该元素放进最小值栈。
--pop
当pop出去的元素不是最小值栈栈顶,则最小值栈不变
如果pop出去的值为当前最小值,则最小值栈也pop出一个元素,此时最小值栈的栈顶就是下一个最小值元素
如果pop出去的值为当前最小值,则最小值栈也pop出一个元素,此时最小值栈的栈顶就是下一个最小值元素
源代码
#include <stdio.h>
#include<stdlib.h>
#include <iostream>
using namespace std;
/**
题目:
定义栈的数据结构 要求添加一个min函数,找出栈的最小元素
要求min、push、pop函数的时间复杂度都为O(1)
思路
牢牢把握住栈【先进后出】的特性,模拟各种实际情况,得出算法
栈结构体中添加一个辅助栈,这里称为【最小值栈】,存储最小值的历史记录
所以该最小值栈的栈顶即为当前栈的最小元素
当push进来的元素值大于、等于最小值栈的栈顶,最小值栈不变
因为根据栈的特性,只有当前最小值元素上面的所有元素都出去的时候,该最小值元素才能pop出去
反之,则将该元素放进最小值栈
当pop出去的元素不是最小值栈栈顶,则最小值栈不变
反之,最小值栈pop出栈顶
这样如果pop出去的值为当前最小值,则最小值栈也pop出一个元素
此时最小值栈的栈顶就是下一个最小值元素
*/
/*
创建栈结点结构体
value 值
nextNode 下一个结点
push() 入栈函数
pop() 出栈函数
min() 求最小值函数
push2() 入栈并且求最小值
pop2() 出栈并且求最小值
*/
struct StackNode{
int value;
static StackNode * minNode;
StackNode * nextNode;
/**
push() 入栈函数
value 入栈的值
返回 栈顶
*/
StackNode * push(int value){
StackNode * top = new StackNode();
if(NULL!=this){
top=this;
StackNode * push = new StackNode();
push->value=value;
push->nextNode=top;
top=push;
}else{
top->nextNode=NULL;
top->value=value;
}
cout<<"入栈,value="<<value<<endl;
return top;
}
/**
pop() 出栈函数
返回 栈顶
*/
StackNode* pop(){
if(NULL!=this){
cout<<"出栈,value="<<this->value<<endl;
return this->nextNode;
}
else{
cout<<"栈已经为空"<<endl;
return this;
}
}
/**
求最小值函数
flag 判断是push还是pop
value push的值或者pop出去的值
*/
void min(bool flag,int value){
//push
if(flag){
//非空
if(NULL!=minNode){
//push进来的值小于等于原来的最小值,则push进入最小值栈
if(value<=minNode->value){
cout<<"最小值栈入栈"<<endl;
minNode=minNode->push(value);
}
}else{
//空,则直接放进去
cout<<"MinNode==NULL"<<endl;
cout<<"最小值栈入栈"<<endl;
minNode=minNode->push(value);
}
}else{
//pop
//非空且pop的值等于最小值,则最小值栈pop
if((NULL!=minNode)&&(minNode->value==value)){
cout<<"最小值栈出栈"<<endl;
minNode=minNode->pop();
}
}
if(NULL!=minNode)
cout<<"现在栈的最小值value="<<minNode->value<<endl;
}
//push+min
StackNode* push2(int value){
StackNode* node=this->push(value);
this->min(true,value);
return node;
}
//pop+min
StackNode* pop2(){
int value = this->value;
StackNode* node=this->pop();
this->min(false,value);
return node;
}
};
//结构体静态变量初始化!
StackNode * StackNode::minNode = NULL;
StackNode * stack;
void main()
{
stack=stack->push2(5);
stack=stack->push2(2);
stack=stack->push2(4);
stack=stack->push2(1);
stack=stack->push2(1);
while(NULL!=stack){
stack=stack->pop2();
}
system("pause");
}
效果图
总结,所有与栈有关的题目,都记住这四个字——”先进后出“