1 栈
1.1栈的概念
栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除操作。栈中的元素遵循先进后出的原则。
- 压栈:栈的插入操作(入数据在栈顶)
- 出栈:栈的删除操作(出数据在栈顶)
1.2 栈的使用
注意注释
package stackdemo;
import java.util.Stack;
public class TestDemo {
public static void main(String[] args) {
Stack<Integer> stack=new Stack<>();
//给栈里面放元素
stack.push(12);
stack.push(23);
stack.push(34);
stack.push(45);
//出栈
//pop弹出并且删除元素
int ret=stack.pop();
System.out.println(ret);//45出,栈中已经没有了45
//peek获取元素但是不删除
int ret1=stack.peek();
System.out.println(ret1);
//栈是否为空
System.out.println(stack.empty());
System.out.println(stack.isEmpty());
}
}
2 栈的应用
1 若进栈序列为1,2,3,4,进栈过程中可以出栈,则下列不可能的一个出栈序列是()A :1,4,3,2
B :2,3,4,1
C :3,1,4,2
D :3,4,2,1
答案:C
进栈过程中可以出栈,比如A选项,先进1 再出1,再进2、进3、进4,再出4、出3、出2,即符合题意。
2 一个栈的初始状态为空。现将元素1、2、3、4、5、 A 、 B 、 C 、 D 、 E 依次入栈,然后再依次出栈,则元素出栈的顺序是()。
A :12345ABCDEB :EDCBA54321
C : ABCDE12345
D :54321EDCBA
答案:B
原因:依次入栈,然后再依次出栈
3 将中缀表达式(a+b+c*d)/e,转成后缀表达式ab+cd*+e/
技巧:(a+b+c*d)/e --->
(1)加括号(((a+b)+(c*d)) / e )
(2)将各个括号里面的运算符拉到括号外面(((a b)+ (c d)*)+ e )/
(3)去掉所有的括号 a b+ c d*+ e /
- 如果是数字就放到栈中
- 如果是操作符,就取出栈顶两个元素,进行运算,把结果写会到栈中,继续遍历字符
- 栈中最后的元素就是表达式的结果
3 练习题
(1)逆波兰表达式求值
有效的算符包括+、—、*、/,每个运算符对象可以是整数,也可以是另一个逆波兰表达式。
注意两个整数之间的除法只保留整数部分。
可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为0的情况。
public class TestDemo {
//求逆波兰表达式
public int evalRPN(String[] tokens){
Stack<Integer> stack=new Stack<>();
for(String x : tokens){
if(! isOperation(x)) {
//说明当前的x是一个数字字符串
stack.push(Integer.parseInt(x));//将字符串变成一个整数
}else{
//弹两个元素
int num2=stack.pop();
int num1=stack.pop();
switch (x){
case "+" :
stack.push(num1+num2);
break;
case "-" :
stack.push(num1-num2);
break;
case "*" :
stack.push(num1*num2);
break;
case "/" :
stack.push(num1/num2);
break;
}
}
}
return stack.pop();
}
//判断s(某个字符串)是不是运算符
private boolean isOperation(String s){
if(s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")){
return true;
}
return false;
}
}
(2)递归逆序打印单链表
class ListNode {//节点
public int val;
public ListNode next;//类型是Node
public ListNode(int val){
this.val=val;
}
}
public class SingleLinkedList {
public ListNode head;
//递归逆序打印单链表
public void printList(ListNode head){//方法1
if(head==null){
return;
}
if(head.next==null){
System.out.println(head.val+" ");
return;
}
printList(head.next);
System.out.print(head.val+" ");
}
public void printList2(){//方法2
Stack<ListNode> stack=new Stack<>();
ListNode cur=head;
while (cur!=null){
stack.push(cur);
cur=cur.next;
}
while (!stack.empty()){//当栈不为空
ListNode tmp=stack.pop();
System.out.print(tmp.val+" ");
}
System.out.println();
}
}
(3)括号匹配
给定一个只包括‘(’,‘)’,‘{’,‘}’,‘[’,‘]’的字符串 s ,判断字符串是否有效。
有效字符串需满足:
1.左括号必须用相同类型的右括号闭合。
2.左括号必须以正确的顺序闭合。
1>遍历字符串,如果是左括号,那么入栈。如果是右括号,则看栈顶元素是不是与之相匹配的。匹配的情况下出栈。
- 当字符串遍历完成之后,栈还不是空的,那么说明左括号多。
- 当遇到右括号之后,发现栈是空的,那么说明右括号多。
- 当 i 是右括号,栈顶元素是左括号,但是这个是不匹配的。此时说明左右括号不匹配。
2>直到栈为空且字符串遍历完成才说明左右括号是匹配的。
//括号匹配
class Solution{
public boolean isValid(String s){
Stack<Character> stack=new Stack<>();
for(int i=0;i<s.length();i++){
char ch=s.charAt(i);
if(ch=='(' || ch=='[' || ch=='{'){
//说明此是是左括号
stack.push(ch);//将左括号放入栈中
}else {
//说明是右括号
//栈空不空 空不匹配-->右括号多,一上来就是右括号
if(stack.empty()){
return false;
}
char top=stack.peek();//获取栈顶元素 一定是一个左括号
if(ch==')' && top=='(' || ch==']' && top=='[' || ch=='}' && top=='{'){
stack.pop();
}else {
return false;//左右括号不匹配
}
}
}
if(!stack.empty()){
return false;//字符串遍历完成,栈里面还有括号。此时说明左括号多
}
return true;
}
}
(4)输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列
4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
1.0<= pushV . length == popV.length <=10002.-1000<= pushV [ i ]<=1000
3. pushV 的所有数字均不相同
//出栈入栈次序匹配
public class Solution{
public boolean IsPopOrder(int [] pushA,int [] popA){
Stack<Integer> stack=new Stack<>();
int j=0;//用来遍历popA数组
for(int i=0;i<pushA.length;i++){
stack.push(pushA[i]);
//j不能越界,栈不能为空
while (j<popA.length && !stack.empty() && stack.peek()==popA[j]){
stack.pop();
j++;
}
}
return stack.empty();
}
}
栈、虚拟机栈、栈帧的区别
答:栈-->数据结构;虚拟机栈-->JVM的内存;栈帧-->当运行函数时,会在Java虚拟机栈上,开辟栈帧给当前函数。
1846

被折叠的 条评论
为什么被折叠?



