栈stack:
(1)栈的基本知识:
(1.1)栈的存储结构:
(1.2)栈的特点:
(2)栈的基本操作:
(2.1)顺序栈的基本操作:
(2.2)链式栈的基本操作:
(3)顺序栈:seqStack
(4)链式栈:linkStack
(5)共享栈:shareStack
(6)栈的应用:
(6.1)表达式求值:expressionValue
(6.2)括号匹配match:
(6.3)求解迷宫问题:maze
(7)栈的扩展操作:
(7.1) O(1)求栈中最小值:
-------------------------------------------
(1)栈的基本知识:
(1.1)栈的存储结构:
顺序栈,链式栈;
(1.2)栈的特点:
后进先出,头进头出,插入和删除在栈顶进行;
栈是一种插入删除受限制的线性表。
(2)栈的基本操作:
(2.1)顺序栈的基本操作:
(2.1)初始化栈init:
(2.2)栈空isEmpty:
(2.3)栈满isFull:
(2.4)进栈push:
(2.5)出栈pop:
(2.6)取栈顶getTop:
(2.7)栈的大小:getSize:
(2.2)链式栈的基本操作:
(3.1)初始化栈init:
(3.2)栈空isEmpty:
(3.3)进栈push:
(3.4)出栈pop:
(3.5)取栈顶getTop:
(2.6)栈的大小:getSize:
(注:链式栈不存在栈满)
(3)顺序栈:seqStack
顺序栈通常用一个数组来存储栈中元素,用下标为0的一端作为栈底,
栈顶设置一个指针top指示栈中元素的变化,称为栈顶指针。
(3.1)顺序栈的定义:
(3.2)顺序栈的五要素:
(3.2.1)方法一:
. 栈空条件:s.top=-1
. 栈满条件: s.top=Maxsize-1
. 元素e进栈:s.top++;s.array[s.top]=e;
. 元素出栈:e=s.array[s.top];s.top--;
. 获取栈顶: returns.array[top];
解析:初始化top=-1;则当前的top这个位置,已经被填入了元素;
所以进栈需要top++;然后赋值;
出栈,直接去top处的值,然后top--;
栈满的条件是top=Maxsize-1;
获取栈顶: returnarray[top];
(3.2.2)方法二:
. 栈空条件:s.top=0
. 栈满条件: s.top=Maxsize
. 元素e进栈:s.array[s.top]=e;s.top++;
. 元素出栈:s.top--;e=s.array[s.top];
. 获取栈顶: returns.array[top-1];
解析:初始化top=0,表示当前top这个位置还没有元素填充,
填充的是top-1;
(3.3)顺序栈的基本操作代码:
(4)链式栈:linkStack
(4.1)链式栈的定义:
(4.2)链式栈的操作:
. 栈空:topNode=NULL orsize=0;
(不带头节点的链式栈)
. 进栈:头插法:建立一个newnode,更新topNode;
. 出栈:删除首节点,更新topNode;
(4.3)链式栈的基本操作代码:
(5)共享栈:shareStack
(5.1)共享栈的图解:
(5.2)共享栈的解析:
两个栈共享一个数组vector[0~MaxSize-1]的空间,从而构成共享栈,数组vector的两端是固定的,分别作为栈1,和栈2的栈底。
(5.3)共享栈的操作:
(5.3.1)栈1的操作:
. 栈空: top1=-1;
. 栈满: top1=top2-1;
. 元素e进栈: top1++;shareArray[top1]=e;
. 出栈:e=shareArray[top1];top1--;
(5.3.2)栈2的操作:
. 栈空:top2=MaxSize-1;
. 栈满: top2=top1+1;
. 元素e进栈: top2--;shareArray[top2]=e;
. 元素出栈:e=shareArray[top2];top2++;
(5.4)共享栈的操作代码:
(6)栈的应用:
(6.1)表达式求值:expressionValue:
(6.1.1)解析:()、*/、+-这几种符号的优先级是不一样的,中缀表达式是有优先级的表达式,不便于在程序中处理,后缀表达式是一种非优先级的表达式,而且不会出现括号。
(6.1.2)步骤:
(1)中缀表达式转后缀表达式:
分析: 后缀表达式与表达式的操作数的排列次序完全相同,只是运算符改变了次序。
所以:
(1)若读到一个操作数,就把它作为后缀表达式的一部分输出;
(2)对于运算符的处理,系统需设置一个存放运算符的栈。
分析:初始时,栈顶设置一个界限符#(与表达式结束符#配成一对)
每当读到一个运算符时,就将其优先级与栈顶位置运算符优先级进行比较,以决定是把所读到的运算符进栈,还是将栈顶位置的运算符作为后缀表达式的一部分输出。
因为: 对于任意两个相继出现的运算符θ1θ2,它们之间的优先关系至多是下面三种关系之一:
θ1<θ2,θ1的优先级低于θ2;
θ1=θ2,θ1的优先级等于θ2;
θ1>θ2,θ1的优先级高于θ2。
(2)优先级解析:
对于+,-,*,/,(,),#,这几种运算符来说,其优先关系可以由算术四则运算规则得到。
(1)先乘除,后加减;
(2)从左到右算;
(3)先括号内,后括号外。
A、由(1)*,/ > +,-;
B、由(2)*>/,/ >*, +>-,->+;
C、由(2)对于+,-,*,/,当θ1=θ2时,令θ1>θ2,即+>+,->-,*>*,/>/;
D、由(3)+,-,*,/的优先级均低于“(”,但高于“)”;
(注:即:+,-,*,/的优先级均低于它们后面的“(”。
高于它们后面的“)”。
)
E、由(3)“(”的优先级均低于+,-,*,/,(;
“)”的优先级均高于 +,-,*,/,);
(注:即:“(”的优先级均低于它后面的+,-,*,/,( 。
“)”的优先级均高于它后面的+,-,*,/,)
)
F、“(” =“)”,表示当左右括号相遇时,括号内的运算已经完成;
H、“#”是表达式的结束符,为了算法简洁,在表达式的最左边也需设一个“#”,构成整个表达式的一对括号;
左“#”的优先级低于+,-,*,/,(;
+,-,*,/,)的优先级高于“#”(结束符);
“#”=“#”表示整个表达式处理完毕。
注意:“)”与“(”,“#”与“)”以及“(”与“#”之间无优先关系,因为表达式中不允许它们相继出现(若出现,则表达式有错),一旦遇见,则可以认为出现了语法错误。
--------------------
中缀表达式转为后缀表达式的算法步骤:
(1)置运算符栈s为空栈,然后将表达式的起始符“#”入栈;
(2)循环:依次读入中缀表达式中一个单词;
A、若是操作数,就将其输出,接着读下一个字符;
B、若是运算符,就赋予x2,比较x2与栈顶运算符x1的优先级;
1. 若x2的优先级高于x1,则将x2进栈,读下一个单词;
2. 若x2的优先级低于x1,x1退栈,并作为后缀表达式的一个单词输出,再转B(即继续比较x2与新的栈顶运算符x1);
3. 若x2的优先级等于x1,且x1为“(”,x2为“)”,则x1退栈,然后继续读下一个单词;
4. 若x2的优先级等于x1,且x1为“#”,x2也为“#”,则算法结束。
范例:
图解1:中缀-后缀1
图解2:中缀-后缀2
(2)后缀表达式求值:
思路:遍历后缀表达式,遇到非操作符的字符则直接压入栈中,如果遇到操作符则从栈中弹出两个对象,进行对应的操作,然后将计算的结果又压入栈中。继续遍历,直到表达式被遍历完成,此时栈中保存的值也就是当前表达式的值。
注意:除法和减法的操作数顺序问题以及除数不能为0的,因为第一次退栈的操作数是运算符后的操作数,第二次退栈的操作数是运算符前的操作数。
(6.1.3)中缀表达式->后缀表达式:
中缀表达式:a*b+c*d-e/f
后缀表达式:ab*cd*+ef/
(6.1.4)表达式求值代码实现:
代码实现2(简洁版):
(6.2)括号匹配match:
(6.3)求解迷宫问题:maze
(6.4)进制转换:
(6.4.1)图解:
(6.4.2)思想:
如:十进制整数转换成n进制:除n取余倒着数(栈实现)
(6.4.3)代码实现
(6.5)路径探索之保存路径:
(7)栈的扩展操作:
(7.1) O(1)求栈中最小值: