首先我们来讲讲什么是栈,主要是介绍我对栈的了解和认识:栈是一种用于存储数据的表,鲜明的特点是先进后出FILO,栈的实现分为数组实现和链表实现。学习栈看中学习栈的思想,通过栈的思想解决一些实际中的问题。Java中有Stack类实现栈的操作。这篇博客主要阐述,栈的基本实现,数组实现和链表实现。

一、栈的模型图

入栈的顺序为:0、1、2、3、 4、 5、6   出栈的顺序为6、5、4、3、2、1、0

二、栈的数组实现

这个栈的实现是通过数组实现的,通过动态的扩充数组的长度来实现无界栈。

代码实现:

 1 package Stack;
 2 
 3 public class Stack1 {
 4     private int stack[];//用于存储栈内元素的数组
 5     private int DEFAULTSIZE=5;//默认初始化栈的存储空间
 6     private int top;//栈顶指针
 7     private int base;//栈底指针
 8     private int nowSize;//栈当前的元素个数
 9     private int sumSizeFlag=1;//当前栈拓展的栈的空间为默认空间大小的倍数
10     //初始化栈,给栈分配内存,初始化一些参数
11     public Stack1() {
12         stack=new int[DEFAULTSIZE];
13         top=0;
14         nowSize=0;
15         base=0;
16     }
17     //给栈进行拓展空间
18     private void enLargeSize(){
19         int []mark=stack;
20         stack=new int[DEFAULTSIZE*sumSizeFlag];
21         for(int i=0;i<nowSize;i++){
22             stack[i]=mark[i];
23         }
24         System.out.println("栈进行了一次存储空间的扩充!");
25     }
26     //入栈操作
27     public void push(int m){
28         if(nowSize==stack.length){
29             sumSizeFlag++;
30             enLargeSize();
31         }
32         stack[nowSize]=m;
33         nowSize++;
34         top++;
35         
36     }
37     //出栈操作
38     public int pop() throws Exception{        
39         if(top==0)
40             throw new Exception("栈空,不能进行出栈操作!");
41         top--;
42         int mark=stack[top];
43         nowSize--;
44         return mark;
45     }
46     public static void main(String[] args) throws Exception {
47         Stack1 stack1=new Stack1();
48         for(int i=0;i<6;i++){
49             stack1.push(i);
50         }
51         
52         for(int i=0;i<6;i++)
53             System.out.print(stack1.pop()+" ");
54         System.out.println();
55         System.out.println(stack1.pop());
56     }
57 }

运行结果:

 1 栈进行了一次存储空间的扩充! 2 5 4 3 2 1 0  3 Exception in thread "main" java.lang.Exception: 栈空,不能进行出栈操作! 4 at Stack.Stack1.pop(Stack1.java:40) 5 at Stack.Stack1.main(Stack1.java:55) 

三、栈的链表实现

这里链表实现栈的操作,需要设置两个(引用)指针,一个专门指向他的上一个节点,另一个指针专门指向它的下一个指针,链表实现栈其实在操作上还是听麻烦的,两个引用的设置还是得很小心的。所以相对于链表实现我跟喜欢数组实现。

代码实现:

 1 //节点类
 2 class Node{
 3     private int date;//存储数据
 4     private Node next;//指向下一个节点
 5     private Node prior;//指向上一个节点
 6     public int getDate() {
 7         return date;
 8     }
 9     public void setDate(int date) {
10         this.date = date;
11     }
12     public Node getNext() {
13         return next;
14     }
15     public void setNext(Node next) {
16         this.next = next;
17     }
18     public Node getPrior() {
19         return prior;
20     }
21     public void setPrior(Node prior) {
22         this.prior = prior;
23     }
24     
25 }
26 public class Satck2 {
27     private Node top;//栈顶指针
28     private Node base;//栈底指针
29     private int nowSize;//栈当前的元素个数
30     //初始化栈,初始化一些参数
31     public Satck2() {
32         Node head=new Node();
33         base=top=head;
34         nowSize=0;
35         head.setPrior(null);
36         head.setNext(null);
37     }
38     
39     //入栈操作
40     public void push(int m){
41         top.setDate(m);    
42         top.setNext(new Node());
43         top.getNext().setPrior(top);//这里需要帮助新创建的节点的prior指针指向前一个节点
44         top=top.getNext();
45         nowSize++;        
46     }
47     //出栈操作(出栈的时候相当于先获得栈顶指针的下一个元素的数据,将这个数据的节点删除)
48     public int pop() throws Exception{        
49         if(nowSize==0)
50             throw new Exception("栈空,没法进行出栈操作!");
51         int mark=top.getPrior().getDate();
52         if(top.getPrior().getPrior()!=null){
53             top.getPrior().getPrior().setNext(top);
54             top.setPrior(top.getPrior().getPrior());
55         }else if(top.getPrior().getPrior()==null){
56             top.setNext(null);
57             top.setPrior(null);
58         }
59         nowSize--;
60         return mark;
61     }
62 
63     public static void main(String[] args) throws Exception {
64          Satck2 stack1=new  Satck2();
65         for(int i=0;i<6;i++){
66             stack1.push(i);
67         }
68         
69         for(int i=0;i<6;i++)
70             System.out.print(stack1.pop()+" ");
71         System.out.println();
72         System.out.println(stack1.pop());
73     }
74 
75 }

 运行结果:

5 4 3 2 1 0 
Exception in thread "main" java.lang.Exception: 栈空,没法进行出栈操作!
    at Stack.Satck2.pop(Satck2.java:51)
    at Stack.Satck2.main(Satck2.java:73)

 三、通过栈思想实现的计算器(实现带括号的整数的加减乘除)

首先需要将中缀式通过栈转化为后缀式,然后使用后缀式通过栈计算算式的答案。

中缀式转化为后缀式的思想:建立一个stack,先对输入的字符串进行转化,转化成字符数组,遍历这个字符数组:

                                    1、当遇到数字时候把他们按顺序存放在一个新的数组中,

                                    2、当遇到符号时,先判断栈是否为空,为空直接进栈,否则判断是否栈中的元素的优先级是否比自己大,比自己大或相等,循环进行出栈操作,将出                                           栈的元素继续放在新的数组中,知道栈空或遇到栈中比自己优先级小的操作符,然后入栈。其中优先级顺序:'('  >  '* '= '/' > '+' = '-'  > ')'  。                                         这里必须强调一下当遇到‘)’则是一直出栈至‘(’为止。

后缀式计算算式答案的思想:建立一个stack,当遇到数字直接入入栈,当遇到符号,则先出栈两次,将两次出栈的数字进行进行相应的计算,然后将结果入栈,这样一直执行下                                         去,直到对数组遍历完成,然后出栈的结果即为答案。

例如:1*(1+2*3)+1

中缀式转为后缀式:

后缀式计算比较简单,这里就不画图了。。。

直接上代码:

  1 package Stack;
  2 
  3 import java.util.Scanner;
  4 import java.util.Stack;
  5 
  6 public class Calculator {
  7     private int fixLength;//用于记录当前字符数组的元素个数
  8     //将中缀式转化为后缀式
  9     public String[] infixToPostfix(char []infix){
 10         String []st=new String[infix.length];
 11         Stack<Character> stack=new Stack<Character>();
 12         int nowLocationMark=0;//记录当前数组重新添加进去的元素个数
 13         String str="";
 14         for(int i=0;i<infix.length;i++){
 15             //System.out.println(stack.size());
 16             if('0'<=infix[i]&&infix[i]<='9'){
 17                 str=str+infix[i];
 18                 if((i==infix.length-1)||('0'>infix[i+1]||infix[i+1]>'9')){
 19                     st[nowLocationMark]=str;
 20                     str="";
 21                     nowLocationMark++;
 22                 }
 23             }else{
 24                 if(stack.isEmpty()){
 25                     stack.push(infix[i]);
 26                 }else{
 27                     if(infix[i]=='('){
 28                         stack.push(infix[i]);
 29                     }else if(infix[i]=='*'||infix[i]=='/'){
 30                         if(stack.peek()=='*'||stack.peek()=='/'){
 31                             while(!stack.isEmpty()&&(stack.peek()!='+'&&stack.peek()!='-')){
 32                                 str=str+stack.pop();
 33                                 st[nowLocationMark]=str;
 34                                 str="";
 35                                 nowLocationMark++;
 36                             }
 37                         }    
 38                         stack.push(infix[i]);
 39                     }else if(infix[i]==')'){
 40                        char mark;
 41                        mark=stack.pop();
 42                        do{
 43                         
 44                            str=str+mark;
 45                            mark=stack.pop();
 46                            st[nowLocationMark]=str;
 47                            str="";
 48                            nowLocationMark++;
 49                        }while(mark!='(');
 50                        //stack.pop();//这里讲'('从数组中删除
 51                        //fixLength=fixLength-2;//这里也需要知道字符数组的长度减小了2
 52                     }else if(infix[i]=='+'||infix[i]=='-'){
 53                         if(stack.peek()=='+'||stack.peek()=='-'||stack.peek()=='*'||stack.peek()=='/'){
 54                             while(!stack.isEmpty()&&stack.peek()!='('){
 55                                 str=str+stack.pop();
 56                                 st[nowLocationMark]=str;
 57                                 str="";
 58                                 nowLocationMark++;
 59                             }
 60                         }
 61                         stack.push(infix[i]);
 62                     }
 63                 }
 64             }
 65         }
 66         //将栈中还没输出的元素出栈操作
 67         while(!stack.isEmpty()){
 68             str=str+stack.pop();
 69             st[nowLocationMark]=str;
 70             str="";
 71             nowLocationMark++;
 72         }
 73         fixLength=nowLocationMark;//将当前字符数组的元素个数记录下来
 74         return st;
 75     }
 76     //用于对后缀表达式进行处理,最后计算出一个答案
 77     public int doPostfix(String []postfix){
 78         //System.out.println(fixLength);
 79         double mark;
 80         Stack<Integer> stack=new Stack<Integer>();
 81         for(int i=0;i<fixLength;i++){
 82             if(postfix[i].equals("*")||postfix[i].equals("/")||postfix[i].equals("+")||postfix[i].equals("-")){
 83                 int mark1=stack.pop();
 84                 int mark2=stack.pop();
 85                 System.out.println(mark1+postfix[i]+mark2);
 86                 switch (postfix[i]) {
 87                 case "*":
 88                     stack.push(mark1*mark2);
 89                     break;
 90                 case "/":
 91                     stack.push(mark2/mark1);
 92                     break;
 93                 case "+":
 94                     stack.push(mark2+mark1);
 95                     break;
 96                 case "-":
 97                     stack.push(mark2-mark1);
 98                     break;
 99                 }
100             }else{
101                 stack.push(Integer.parseInt(postfix[i]));
102             }
103         }
104         
105         return stack.pop();
106     }
107     //计算器启动方法
108     public void startCalculator(){
109         Scanner sc=new Scanner(System.in);
110         while(sc.hasNext()){
111             //sc.nextLine();
112             String str=sc.nextLine();
113             char []fix=str.toCharArray();
114             System.out.println(doPostfix(infixToPostfix(fix)));
115         }
116     }
117     public static void main(String[] args) {
118         Calculator calculator=new Calculator();
119         calculator.startCalculator();
120         //之前用于测试的代码
121         /*char []ch={'1','+','(','1','+','2','*','3','1',')','*','2','/','2'};
122         String[] s=calculator.infixToPostfix(ch);
123         for(int i=0;i<s.length;i++){
124             System.out.print(s[i]);
125         }
126         System.out.println(calculator.doPostfix(s));*/
127     }
128 
129 }

运行结果:

1+3*(1+2+3*4)+1
2+1
4*3
12+3
15*3
45+1
1+46
47

注:第一行为输入,第二行到第七行为运算过程,第八航为结果。

这个计算器的代码想的比较简单,可能有的可能没考虑到,只能进行带括号的加减乘除运算,甚至还不能进行浮数计算,以简单为主,主要思想就是通过栈的思想来实现计算器,主要是验证栈思想。

posted on 2017-05-31 21:36  小调~  阅读(401)  评论(0编辑  收藏  举报

导航