栈
-
基本介绍
<1> 限制性线性表,元素只能在一端插入和删除的特殊线性表
<2> 允许插入删除的一端称栈顶Top
<3> 固定的一端称栈底Button
<4> 先进后出
-
应用场景
<1> 子程序的调用
<2> 递归调用
<3> 表达式的转换与求值:前 后 中缀表达式
<4> 二叉树的遍历
<5> 图的深度优先搜素 -
数组模拟栈
public class ArrayStack {
public int maxSize;//栈最大容量
public int top=-1;//栈顶元素
public int stack[];
public ArrayStack(int maxSize){
this.maxSize=maxSize;
stack = new int[this.maxSize];
}
/**
* 栈满
* @return
*/
public boolean isFull(){
return top==maxSize-1;
}
/**
* 栈空
* @return
*/
public boolean isEmpty(){
return top==-1;
}
/**
* 入栈
* @param value
*/
public void push(int value){
if(isFull()){
System.out.println("栈满!");
return;
}
top++;
stack[top]=value;
}
/**
* 出栈
* @return
*/
public int pop(){
if(isEmpty()){
throw new RuntimeException("栈空!");
}
int value=stack[top];
top--;
return value;
}
/**
* 获取栈顶元素
* @return
*/
public int peek(){
return stack[top];
}
/**
* 遍历栈
*/
public void list(){
if(isEmpty()){
throw new RuntimeException("栈空!");
}
for(int i=top;i>=0;i--){
System.out.print(stack[i]+"\t");
}
}
}
- 链表模拟栈
public class LinkedListStack {
public LNode top;//栈顶元素
public LNode head;
//在链表head.next进行插入 删除
public LinkedListStack(){
head = new LNode(0,null);
top=head.next;
}
/**
* 栈空
* @return
*/
public boolean isEmpty(){
return top==null;
}
/**
* 入栈
* @param value
*/
public void push(LNode stack){
LNode cur = head.next;
head.next=stack;
stack.next=cur;
top=head.next;
}
/**
* 出栈
* @return
*/
public LNode pop(){
if(isEmpty()){
throw new RuntimeException("栈空!");
}
LNode value=head.next;
head.next=head.next.next;
top=head.next;
return value;
}
/**
* 获取栈顶元素
* @return
*/
public int peek(){
return top.data;
}
/**
* 遍历栈
*/
public void list(){
if(isEmpty()){
throw new RuntimeException("栈空!");
}
LNode cur=head.next;
while(cur!=null){
System.out.print(cur.data+"\t");
cur=cur.next;
}
}
}
- 栈实现综合计算器(中缀表达式为例)
思路:
1.通过一个index遍历表达式
2.若是数字,直接入数字栈——注意多位数的问题
1)用一个while循环得到下一个index字符,若是数字则用字符串拼接
3.若是字符
1)若此时栈空,直接压入字符栈
2)若此时栈非空,则判断该字符与栈顶字符的优先级
1》若 该字符优先级>栈顶字符优先级 直接压栈
2》若 该字符优先级<=栈顶字符优先级 数字栈弹出两个 字符弹出 一个,计算结果压入数字栈 该字符也压入字符栈
4.当表达式扫描完毕(index>字符串表达式的长度) 但此时还有一组计算应出栈计算完后, 将结果压到数字栈
5.最后只有一个数字就是表达式的结果
public class Calculator {
ArrayStack numStack = new ArrayStack(10);//数字栈
ArrayStack operStack = new ArrayStack(10);//符号栈
/**
* 判断是不是运算符
* @param val
* @return
*/
public boolean isOper(char val){
return (val=='+')||(val=='-')||(val=='*')||(val=='/');
}
/**
* 返回运算符的优先级
* @param oper
* @return
*/
public int priority(int oper){
//此时假定只有=-*/运算
if(oper=='*'||oper=='/'){
return 2;
}else if(oper=='+'||oper=='-'){
return 1;
}else{
return -1;
}
}
/**
* 计算
* @param num1
* @param num2
* @param oper
* @return
*/
public int cal(int num1,int num2,int oper){
int res=0;
switch(oper){
case '+':
res = num1+num2;
break;
case '-':
res = num2-num1;//注意顺序
break;
case '*':
res = num1*num2;
break;
case '/':
res = num2/num1;//注意顺序
break;
default:
break;
}
return res;
}
/**
* 返回最终结果
* @param expression
* @return
*/
public int calculator(String expression){
int index=0;//用于扫描
int num1=0;
int num2=0;
int oper=0;//符号
int res=0;//结果
char ch;//将扫描到的char保存到ch
String keepNum="";//拼接多位数
while(true){
//从表达式中截取一个子符
ch=expression.substring(index,index+1).charAt(0);
if(isOper(ch)){//是符号
if(!operStack.isEmpty()){//符号栈非空
if(priority(ch)<=priority(operStack.peek())){
//当前优先级<=栈顶优先级
num1=numStack.pop();
num2=numStack.pop();
oper=operStack.pop();
operStack.push(ch);
res=cal(num1, num2, oper);
numStack.push(res);
}else{
operStack.push(ch);
}
}else{
operStack.push(ch);
}
}else{//是数字
keepNum+=ch;//多位数的拼接
//判断是不是多位数字
if(index==expression.length()-1){//如果到最后直接拼接入栈
numStack.push(Integer.parseInt(keepNum));
}else{
if(isOper(expression.substring(index+1,index+2).charAt(0))){//是符号入栈
numStack.push(Integer.parseInt(keepNum));
keepNum="";
}
}
}
index++;
if(index>=expression.length()){
break;
}
}
//扫描完后还剩下最后一组计算
while(true){
if(operStack.isEmpty()){
break;
}
num1=numStack.pop();
num2=numStack.pop();
oper=operStack.pop();
res=cal(num1, num2, oper);
numStack.push(res);
}
return numStack.pop();
}
}
- 波兰计算器(前缀表达式的计算器求值)
思路:从右至左扫描表达式,遇到数字时压入数字栈,遇到运算符时,弹出栈顶两个数做相应计算,其计算结果入栈,重复,直到表达式最左端 - 逆波兰计算器(后缀表达式的计算器求值)
思路:
1.拆分字符串到List中
2.从左到右扫描List
3.若是数字,直接压入栈——匹配多位数 使用正则表达式判断 matches("\d+")
4.若是字符,弹出两个 加上该字符计算 将结果保存在栈中
5.重复扫描步骤直到扫描完毕
6.最后只有一个数字就是表达式的结果
其中包含中缀转后缀
思路:
1.中缀表达式转成对应的List
2.中缀List转成后缀List思路
1)从左到右扫描中缀List
2)若是数 放入List
3)若是符
1》若栈空 则直接将此符压入栈
2》若栈非空 则比较优先级
该运算符优先级>栈顶符号优先级 将改符号压入栈
该运算符优先级<=栈顶符号优先级 将栈顶符号弹出并放入List 重复3)
4)若是()
"("直接压入栈
")"依次将栈顶符号弹出并放入List中 直到遇到(为止 注意要舍弃这对()不放List中
5)扫描到表达式最右端 将栈中剩下的符号依次放入List
public class PolandNotation {
ArrayStack numStack = new ArrayStack(10);
/**
* 判断是不是运算符
* @param val
* @return
*/
public boolean isOper(char val){
return (val=='+')||(val=='-')||(val=='*')||(val=='/');
}
/**
* 返回运算符的优先级
* @param oper
* @return
*/
public int priority(int oper){
//此时假定只有=-*/运算
if(oper=='*'||oper=='/'){
return 2;
}else if(oper=='+'||oper=='-'){
return 1;
}else{
return -1;
}
}
/**
* 计算
* @param num1
* @param num2
* @param oper
* @return
*/
public int cal(int num1,int num2,int oper){
int res=0;
switch(oper){
case '+':
res = num1+num2;
break;
case '-':
res = num2-num1;//注意顺序
break;
case '*':
res = num1*num2;
break;
case '/':
res = num2/num1;//注意顺序
break;
default:
break;
}
return res;
}
/**
* 将数字字符放入ArrayList中:表达式用空格分开
* @param expression
* @return
*/
public List<String> getListString(String expression){
String[] split = expression.split(" ");
List<String> list = new ArrayList<String>();
for(String ele:split){
list.add(ele);
}
return list;
}
/**
* 返回最终结果
* @param expression
* @return
*/
public int calculator(List<String> ls){
int num1=0;
int num2=0;
int res=0;//结果
for(String item:ls){
if(item.matches("\\d+")){//正则表达式 匹配的是 多位数
numStack.push(Integer.parseInt(item));
}else{
num1=numStack.pop();
num2=numStack.pop();
res=cal(num1, num2, item.charAt(0));
numStack.push(res);
}
}
return numStack.pop();
}
/
/**
* 中缀表达式转成对应的List
* @param expression
* @return
*/
public List<String> toInfixExpressionList(String expression){
List<String> list = new ArrayList<String>();
int index=0;
char c;//遍历的每个字符串
String str;//对多位数的拼接
do{
if((c=expression.charAt(index))<48||(c=expression.charAt(index))>57){
//非数字
list.add(""+c);
index++;
}else{
//是数--考虑多位
str="";
while(index<expression.length()&&(c=expression.charAt(index))>=48&&(c=expression.charAt(index))<=57){
str+=c;//拼接
index++;
}
list.add(str);
}
}while(index<expression.length());
return list;
}
/**
* 中缀List转成后缀List
* @param ls
* @return
*/
public List<String> parseSuffixExpressionList(List<String> ls){
ArrayStack2 stack = new ArrayStack2(10);//暂存符号
List<String> list = new ArrayList<String>();//存后缀表达式
Operation op = new Operation();
for(String item:ls){
if(item.matches("\\d+")){//是数字
list.add(item);
}else if(item.equals("(")){
stack.push(item);
}else if(item.equals(")")){
while(!stack.peek().equals("(")){
list.add(stack.pop());
}
stack.pop();
}else{//是符号
//栈非空
while(!stack.isEmpty()&&op.getValue(item)<=op.getValue(stack.peek())){
list.add(stack.pop());
}
stack.push(item);
}
}
while(!stack.isEmpty()){
list.add(""+stack.pop());
}
return list;
}
}