数据结构之栈
来源:互联网 发布:mysql like 编辑:程序博客网 时间:2024/06/10 03:12
一、栈(Stack)的结构
数据先进先出(first in last out)如图所示:
例如日常生活中我们把盘子摞起来,最先放置的盘子,最后才能取出。
二、栈操作实例
如下图所示:
● Stack()构造函数创建一个栈
● empty()检查这个栈是否为空(true or false)
● push(5)往栈里插入元素5
● pop()删除顶层元素x,并且x作为返回元素交给上层的使用者
● top()返回顶层元素y
● size()返回元素的个数
三、栈的实现
栈既然输入序列的特例,故可直接基于列表或向量派生,将向量的末端作为栈顶时,时间复杂度为O(1)。
Note:需要特别说明,我们也可以将向量的顶端作为栈顶,但是插入和删除操作都会涉及到向量中的所有元素,则入栈和出栈的时间复杂度为O(n)
C++中有Stack模版类:
s.empty() //如果栈为空返回true,否则返回false s.size() //返回栈中元素的个数 s.pop() //删除栈顶元素但不返回其值 s.top() //返回栈顶的元素,但不删除该元素 s.push() //在栈顶压入新元素
四、栈的应用
(1)逆序输出问题(conversion)
输出次序和实际输出颠倒
递归深度和输出长度不易预知
EX:进制转换问题
按进制转换的定义,整除法算出的结果逆序输出,我们可以把整除的结果依次入栈,再出栈,则得到最终结果。
(2)递归嵌套(stack permtation + parenthesis)
具有自相似性的问题可递归描述,但分支位置和嵌套深度不固定
EX1:括号匹配问题,leetcode No20
bool isValid(string s) { stack<char> res; //使用栈记录已发现但尚未匹配的左括号 for(int i=0;i<s.size();i++) //逐一检查当前字符 { if(s[i]=='('||s[i]=='{'||s[i]=='[') //遇到左括号,进栈 res.push(s[i]); else if(s[i]==')'||s[i]=='}'||s[i]==']') //遇右括号 { if(res.empty()==1) //若栈此时为空,返回false return false; if((res.top()=='('&&s[i]==')')||(res.top()=='{'&&s[i]=='}')||(res.top()=='['&&s[i]==']')) res.pop(); //若栈顶元素和当前元素匹配,则出栈 else return false; } } return res.empty();
EX2:栈混洗
定义:栈混洗就是根据某种规则,对栈中的元素进行重新排列
Note:用<表示栈顶,]表示栈底
初始情况:A=<a1,a2,...,an]
B=S=Φ
规则:只允许将A的顶元素弹出并压入S,或将S的顶元素弹出并压入B
若经过一系列以上操作后,A中元素全部转入B中
结束情况:B=[ak1,ak2,...,akn>
则称之为A的一个栈混洗(stack permutation),输入同一序列,可能有多种栈混洗。
对于长度为n的序列,可能的栈混洗总数SP(n)=catalan(n)=(2n)!/((n+1)!n!)。
甄别:那么我们如何甄别一个排列是不是栈混洗,先说一个简单的情况<1,2,3],n=3,SP(3)=5,而3的全排列个数为6,所以只有一种情况是非法的,这个情况就是[3,1,2>,因为3是需要第一个进栈,那么为了让3第一个进栈,那么2,1必须先进S,那么3后面只能是2。
一般情况下,在一个栈中,对于任何1小于等于i<j<k小于等于n,[...,k,...,i....,j,...>则必非栈混洗。(充要条件)
A permutation is a stack permutation iff it does NOT involve the permutation(312)
Algorithm:按照甄别的充要条件我们可以写出O(n^3)的甄别算法(Too Slow)
我们还可以得到一个改进的性质,即[p1,p2,...,pn>是<1,2,...,n]的栈混洗,当且进当对于任意的i<j不含模式[ ...,j+1, ..., i , ... , ... >这样我们可以得到一个O(n^2)的算法。
O(n)算法,直接借助栈A、B和S,模拟混洗过程,每次S.pop()之前,检测S是否为空,或需弹出的元素在S中,却非顶元素。即如果我们直接模拟这样一种栈混洗的过程,建立三个栈,先后完成push()...pop()...push()的操作,保证能依次得到目标序列,那么就可以确定这样的序列是可以得到的,反之就不能得到,这样的时间度最小为O(n)。
(3)延迟缓冲(evaluation)
线性扫描算法模式中,在预读够长之后,方能确定可处理的前缀
EX:中缀表达式(infex)求值
Question: 给定语法正确的算数表达式S,计算与之对应的数值
Algorithm:使用两个栈,一个栈存放运算符,一个栈存放操作数,还需要一个运算符的优先级表
具体实例可以参照学堂在线的数据结构(邓俊辉)栈这一节,有非常详细的讲解过程
(4)栈式计算
RPN:逆波兰表达式(Reverse Polish Notation)
基于栈结构的特定计算机模式
中缀表达式(infix):由运算符(operator)和操作数(operand)组成的表达式中不使用括号(parenthesis-free),即可表示带优先级的运算关系
缺点:定义混乱,逻辑复杂
RPN:哪个运算符先出现就先计算
举个例子:0!1+23!4-5^-67*-8-9+
只需要一个辅助栈
infix-postfix的转化,目标是消除所有的括号
例如:(0!+1)^(2*3!+4-5)
假设:事先未就运算符之间的优先级关系做过任何约定
1)用括号显式地表示优先级
2)将运算符移到对应的右括号后
3)抹去所有括号
4)稍事整理,即得逆波兰表达式
Note:运算符的相对位置会发生变化,但是操作数的相对位置不会变化
Algorithm:中缀表达式求值过程其实就把RPN求解出来了
0 0
- java数据结构之栈
- 数据结构之顺序栈
- 数据结构之链栈
- 数据结构之栈
- 数据结构复习之【栈】
- 数据结构之栈
- 数据结构之栈
- 数据结构之栈实现
- 数据结构学习之栈
- 数据结构之栈
- 数据结构之栈
- 复习数据结构之栈
- 数据结构之栈
- 数据结构之栈
- 大话数据结构之栈
- 数据结构之顺序栈
- 数据结构之链式栈
- 数据结构之顺序栈
- HDU 2072 单词数 set使用
- iOS 常用第三方库
- Number Sequence 找规律
- 多线程中创建单例模式的双重锁定
- Encode and Decode Strings
- 数据结构之栈
- CTF【每日一题20160623】dotNet逆向分析
- imx6q yocto 添加自己的应用程序
- hdu 1051 //多次贪心 (水题)
- SpringMVC静态资源拦截问题
- Spring注解@Component、@Repository、@Service、@Controller区别
- JStorm/Storm的调试:本地运行模式
- 事务处理
- ACM/ICPC竞赛STL--pair