C语言强化(二)设计可以求最小元素的栈

上一篇详解了二叉树转双向链表,此篇作为【C语言强化】系列第二篇,来聊聊有关栈的一道题,

通过这道题,你可以掌握

  • 如何使用栈“先进后出"的特性
  • 如何巧妙地借助辅助栈
  • 如何在结构体中定义可共享的静态成员变量

题目

看似很简单的求最小值函数,思路有很多很多。笔者首先想到每次push入栈都进行一次排序,使这个栈的栈顶永远是最小元素,然后就发现这是一个很蠢很蠢的想法,第一这样做会改变了栈的结构,第二不满足题目对时间复杂度的要求。

愚蠢归愚蠢,还是有点用的。既然不能改变原来栈的结构,那为何不弄俩栈呢?辅助栈的想法由此而出。

接下来是时间复杂度的问题,显然每次都进行排序是不可行的了,那么是否可以记录保存每个最小值的下一个最小值呢,也就是说,当我当前这个最小值被pop出去后,我要知道下一个最小值是哪个。这时栈的【先进后出】特性就派上用场了。

头脑风暴到此结束。下面是具体思路

牢牢把握住栈【先进后出】的特性,模拟各种实际情况,得出算法

辅助栈:

栈结构体中添加一个辅助栈,这里称为【最小值栈】,存储最小值的历史记录,所以该最小值栈的栈顶即为当前栈的最小元素

算法实现:

--push

当push进来的元素值大于、等于最小值栈的栈顶,最小值栈不变,因为根据栈的特性,只有当前最小值元素上面的所有元素都出去的时候,该最小值元素才能pop出去,否则该最小值元素用于是最小值。

反之,当push进来的元素值小于最小值栈的栈顶,则将该元素放进最小值栈。

--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");
}

效果图

总结,所有与栈有关的题目,都记住这四个字——”先进后出“

时间: 2024-08-28 02:32:07

C语言强化(二)设计可以求最小元素的栈的相关文章

设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈

小结: 1. 常数时间内检索到最小元素 最小栈 - 力扣(LeetCode)https://leetcode-cn.com/problems/min-stack/ 设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈. push(x) -- 将元素 x 推入栈中. pop() -- 删除栈顶的元素. top() -- 获取栈顶元素. getMin() -- 检索栈中的最小元素. 示例: MinStack minStack = new MinStack(); minSt

包含最小元素的栈

题目:设计包含min函数的栈. 定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素. 要求函数min.push以及pop的时间复杂度都是O(1). 文件分布: 头文件和main文件 头文件:代码 #include <stack> #include <assert.h> using namespace std; template <typename T> class stackWithMin{ private : stack<T> m_data;

旋转数组,求最小元素

题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1.NOTE:给出的所有元素都大于0,若数组大小为0,请返回0. 如果,要求在排序的数组中查找一个数字或者统计某个数字出现的次数,都可以尝试二分查找算法 分析: 旋转之后的数组实际上可以划分成两个有序的子数组:前面子数组的大小都大于后面子数组中的元素 注意到实际上最小的元素就是两个

C语言强化(十)求 1+2+…+n | 要求:不使用关键字

大家五一节快乐啦!劳动光荣! 一大早起来刷刷算法题,脑力劳动劳动,结果就发现了这么道神题~ 通过这道题,你可以学会: 用自己的语言去实现高级语言提供的快捷工具 题目:求 1+2+-+n, 要求不能使用乘除法. for. while. if. else. switch. case 等关键字以及条件判断语句(A?B:C) 我了个去..不能使用关键字,那不是自废武功吗?? 淡定淡定~~想想,当我们使用for.while的时候,高级语言都做了些什么,他们那边的世界可没有for和while. 所以,for

C语言强化(九)翻转句子中单词的顺序

这是到很常见的题目,非常简单,但你用到数据结构了吗,或者说你用对了吗? 通过这道题,你可以掌握: 如何将用户的输入,输出到控制台 如何分割字符串 如何正确使用数据结构 题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变. 句子中单词以空格符隔开.标点符号和普通字母一样处理. 例如输入"I am a student.",则输出"student. a am I". 思路 一.获取字符串 首先要能够获取到用户输入的一串字符串,有两点需要注意: 1.如果使

C语言强化(十一)二叉树镜像变化 | 要求:不使用递归

用了这么久的递归,现在不让用递归了,你行么? 通过这道题,你可以学会 如何镜像变化一棵二叉树 什么是递归的本质 如何巧妙地使用辅助栈 题目: 输入一颗二元查找树,将该树转换为它的镜像, 即在转换后的二元查找树中,左子树的结点都大于右子树的结点. 要求: 不使用递归 例如输入: 输出: 将二叉树镜像变化的方法很简单,只要把所有节点的左右节点对调就行了,使用递归可以非常容易的实现. 如下为递归方法实现镜像变化的函数 /** 二叉树镜像变化--递归方法实现 */ void Revertsetree_R

如何求最小三元组距离

题目描述: 已知三个升序整数数组a[l], b[m]和c[n].请在三个数组中各找一个元素,使得组成的三元组距离最小. 三元组的距离定义是:假设a[i].b[j]和c[k]是一个三元组,那么距离为:Distance = max(|a[i]–b[j]|,|a[i]–c[k]|,|b[j]–c[k]|)请设计一个求最小三元组距离的最优算法,并分析时间复杂度. 关键公式:max(|a[i]–b[j]|,|a[i]–c[k]|,|b[j]–c[k]|) = (abs(a[i]-b[j])+abs(a[i

阿里巴巴笔试题求最小三元组距离

已知三个升序整数数组a[l], b[m]和c[n].请在三个数组中各找一个元素,是的组成的三元组距离最小.三元组的距离定义是:假设a[i].b[j]和c[k]是一个三元组,那么距离为: Distance = max(|a[ I ] – b[ j ]|, |a[ I ] – c[ k ]|, |b[ j ] – c[ k ]|) 请设计一个求最小三元组距离的最优算法,并分析时间复杂度. #include<iostream> using namespace std; int Max(int a,i

[算法]求栈中最小元素

如何用O(1)的时间复杂度求栈中最小元素 解题思路: 我们经常会采用空间换取时间提高时间复杂度.我们可以使用两个栈结构,一个栈用来存储数据,另一个栈用来存储栈中的最小元素.思路如下:如果当前入栈的元素比原来栈中的最小值还小,则把这个值压入保存最小元素的栈中:在出栈时,如果当前入栈的元素恰好为当前栈中的最小值,保存最小值的栈顶元素也出栈,使得当前最小值变为其入栈之前的那个最小值. 实现代码如下: package 求栈中最小元素; /** * 用链表方式实现栈 * @author dream * *