棧詳解及java實現


導讀

  棧和隊列是有操作限制的線性表。

目錄

1、棧的概念、特點、存儲結構。

2、棧的java實現及運用。

概念

  棧是一種只允許在一端進行插入或刪除的線性表。

1、棧的操作端通常被稱為棧頂,另一端被稱為棧底。
2、棧的插入操作稱為進棧(壓棧|push);棧刪除操作稱為出棧(彈棧|pop)。

特點

  棧就像一個杯子,我們只能從杯口放和取,所以棧中的元素是“先進后出”的特點。

存儲結構

  順序存儲的棧稱為順序棧;鏈式存儲的棧稱為鏈式棧。

java實現

  我們可以圍繞棧的4個元素來實現棧:

2狀態:是否棧空;是否棧滿。

2操作:壓棧push;進棧pop。

順序棧的實現

  順序棧示意圖:

 1 package test;
 2 /**
 3  * 
 4  * @author Fzz
 5  * @date 2018年1月1日
 6  * @Description TODO:
 7  * 順序棧(SqStack)一般用數組來實現,主要有四個元素:2狀態2操作。
 8  * 2狀態:棧空?;棧滿?
 9  * 2操作:壓棧push;彈棧pop。
10  * @param <T>
11  */
12 public class SqStack<T> {
13     private T data[];//用數組表示棧元素
14     private int maxSize;//棧空間大小(常量)
15     private int top;//棧頂指針(指向棧頂元素)
16     
17     @SuppressWarnings("unchecked")
18     public SqStack(int maxSize){
19         this.maxSize = maxSize;
20         this.data = (T[]) new Object[maxSize];//泛型數組不能直接new創建,需要使用Object來創建(其實一開始也可以直接使用Object來代替泛型)
21         this.top = -1;//有的書中使用0,但這樣會占用一個內存
22     }
23 
24     //判斷棧是否為空
25     public boolean isNull(){
26         boolean flag = this.top<=-1?true:false;
27         return flag;
28     }
29     
30     //判斷是否棧滿
31     public boolean isFull(){
32         boolean flag = this.top==this.maxSize-1?true:false;
33         return flag;
34     }
35     
36     //壓棧
37     public boolean push(T vaule){
38         if(isFull()){
39             //棧滿
40             return false;
41         }else{
42             data[++top] = vaule;//棧頂指針加1並賦值
43             return true;
44         }
45     }
46 
47     //彈棧
48     public T pop(){
49         if(isNull()){
50             //棧為空
51             return null;
52         }else{
53             T value = data[top];//取出棧頂元素
54             --top;//棧頂指針-1
55             return value;
56         }
57     }
58     
59 }
SqStack

   測試:

package test;

import org.junit.Test;

public class test {
    
    @Test
    public void fun(){
        //初始化棧(char類型)
        SqStack<Character> stack = new SqStack<Character>(10);
        
        //2狀態
        System.out.println("棧是否為空:"+stack.isNull());
        System.out.println("棧是否已滿:"+stack.isFull());
        
        //2操作
        //依次壓棧
        stack.push('a');
        stack.push('b');
        stack.push('c');
        //依次彈棧
        System.out.println("彈棧順序:");
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
    }
}

鏈式棧的實現

   鏈式棧示意圖:

 1 package test;
 2 
 3 /**
 4  * @author Fzz
 5  * @date 2018年1月1日
 6  * @Description TODO:
 7  * 鏈棧(LinkStack)用鏈表來實現,主要有四個元素:2狀態2操作。
 8  * 2狀態:棧空?;棧滿(邏輯上永遠都不會棧滿,除非你的電腦沒內存了^_^)。
 9  * 2操作:壓棧push;彈棧pop。
10  * @param <T>
11  */
12 class LinkStack<T>{
13     //棧頂節點
14     private LinkNode<T> top;
15     
16     //初始化1
17     public LinkStack(){
18         this.top = new LinkNode<T>();
19     }
20     
21     //初始化棧
22     public void initStack(){
23         this.top.setData(null);
24         this.top.setNext(null);
25     }
26     //是否棧空
27     public boolean isNull(){
28         boolean flag = top.getNext()==null?true:false;
29         return flag;
30     }
31     
32     //壓棧
33     public void push(LinkNode<T> node){
34         if(isNull()){
35             //棧空,即第一次插入
36             top.setNext(node);
37             node.setNext(null);//該句可以省略(首次插入的元素為棧底元素)
38         }else{
39             node.setNext(top.getNext());
40             top.setNext(node);
41         }
42     }
43     
44     //彈棧
45     public LinkNode<T> pop(){
46         if(isNull()){
47             //棧空無法彈棧
48             return null;
49         }else{
50             LinkNode<T> delNode = top.getNext();//取出刪除節點
51             top.setNext(top.getNext().getNext());//刪除節點
52             return delNode;
53         }
54     }
55 }
56 
57 
58 //鏈式棧節點(外部類實現,也可以使用內部類)
59 class LinkNode<T>{
60     private T data;//數據域
61     private LinkNode<T> next;//指針域
62     
63     //初始化1
64     public LinkNode(){
65         this.data = null;
66         this.next = null;
67     }
68     
69     //初始化2
70     public LinkNode(T data) {
71         super();
72         this.data = data;
73         this.next = null;
74     }
75     public T getData() {
76         return data;
77     }
78     public void setData(T data) {
79         this.data = data;
80     }
81     public LinkNode<T> getNext() {
82         return next;
83     }
84     public void setNext(LinkNode<T> next) {
85         this.next = next;
86     }
87 }
LinkStack

  測試:

 1 package test;
 2 
 3 import org.junit.Test;
 4 
 5 public class test {
 6     
 7     @Test
 8     public void fun(){
 9         LinkStack<Character> ls = new LinkStack<Character>();
10         
11         //1狀態
12         System.out.println("棧是否為空:"+ls.isNull());
13         
14         //2操作
15         //依次壓棧
16         ls.push(new LinkNode<Character>('a'));
17         ls.push(new LinkNode<Character>('b'));
18         ls.push(new LinkNode<Character>('c'));
19         
20         //依次彈棧
21         System.out.println("彈棧順序:");
22         System.out.println(ls.pop().getData());
23         System.out.println(ls.pop().getData());
24         System.out.println(ls.pop().getData());
25     }
26 }

棧的應用

  棧結構是很基本的一種數據結構,所以棧的應用也很常見,根據棧結構“先進后出”的特點,我們可以在很多場景中使用棧,下面我們就是使用上面我們已經實現的棧進行一些常見的應用:十進制轉N進制、行編輯器、校驗括號是否匹配、中綴表達式轉后綴表達式、表達式求值等。

十進制轉換為N進制

  如將十進制123456轉換為16進制,我們需要用123456除以16后取余壓棧,然后用商繼續除以16取余壓棧,重復以上操作,直到商為0,這樣保存在棧中的余數從棧頂到棧底開始排列形成的數字就是16進制了。(注:大於等於10的余數我們要用字母來表示)。

 1 package test;
 2 
 3 public class StackUtils{
 4     public static SqStack<?> ss ;
 5     
 6     //彈棧出所有元素
 7     public static Object[] popAll(SqStack<?> s){
 8         ss = s;
 9         if(ss.isNull()){
10             return null;
11         }else{
12             Object[] array = new Object[ss.getTop()+1];
13             int i = 0;
14             while(!ss.isNull()){
15                 array[i]=ss.pop();
16                 i++;
17             }
18             return array;
19         }
20     }
21     
22     //使用棧進行進制裝換
23     public static String integerToNhex(Integer num,int hex){
24         //對傳入的進制進行判斷
25         if(hex<=0||hex>36){
26             return "請輸入有效的進制";
27         }else if(num==0){
28             return "0";
29         }else if(num>0){//正數
30             SqStack<Integer> stack = new SqStack<Integer>(16);
31             int index = num;
32             while(num!=0){
33                 num = num / hex ;
34                 int remainder = index % hex;//取余壓棧
35                 stack.push(remainder);
36                 index = num;
37             }
38             Object[] o = popAll(stack);//彈棧取出余數
39             StringBuilder sb = new StringBuilder();
40             for(Object i : o){
41                 int in = (int)i;
42                 //取出的數字如果>=10需要用字母代替
43                 if(in>=10){
44                     char c = (char) ('a'+in-10);
45                     sb.append(c);
46                 }else{
47                     sb.append(i);
48                 }
49             }
50             return sb.toString();
51         }else{//負數
52             num = -num;//先去負號
53             SqStack<Integer> stack = new SqStack<Integer>(16);
54             int index = num;
55             while(num!=0){
56                 num = num / hex ;
57                 int remainder = index % hex;//取余壓棧
58                 stack.push(remainder);
59                 index = num;
60             }
61             Object[] o = popAll(stack);//彈棧取出余數
62             StringBuilder sb = new StringBuilder();
63             sb.append("-");//添加負號
64             for(Object i : o){
65                 int in = (int)i;
66                 //取出的數字如果>=10需要用字母代替
67                 if(in>=10){
68                     char c = (char) ('a'+in-10);
69                     sb.append(c);
70                 }else{
71                     sb.append(i);
72                 }
73             }
74             return sb.toString();
75         }
76     }
77     
78 }
StackUtils

  測試:

package test;

import org.junit.Test;

public class test {
        @Test
    public void fun(){
        String s = StackUtils.integerToNhex(123456, 16);
        System.out.println("轉換得到的16進制數為:"+s);
    }
}

校驗括號是否匹配

 1 package test;
 2 
 3 public class StackUtils{
 4     
 5     //表達式括號是否匹配()[]{}
 6     public static boolean isMatch(String str) {  
 7         SqStack<Character> stack = new SqStack<Character>(str.length()+1);  
 8         char[] arr = str.toCharArray(); 
 9         for (char c : arr) {  
10             //遇到左括號進棧
11             if(c=='('||c=='['||c=='{'){
12                 stack.push(c);
13             }
14             //遇到右括號匹配棧頂符號
15             else if(c==')'){
16                 if(stack.isNull()){
17                     return false;//棧為空,匹配失敗
18                 }else if(stack.pop()=='('){
19                     continue;//匹配成功繼續下一次循環
20                 }else{
21                     return false;//匹配不成功代表該表達式不符合規則
22                 }
23             }
24             else if(c==']'){
25                 if(stack.isNull()){
26                     return false;//棧為空,匹配失敗
27                 }else if(stack.pop()=='['){
28                     continue;//匹配成功繼續下一次循環
29                 }else{
30                     return false;//匹配不成功代表該表達式不符合規則
31                 }
32             }
33             else if(c=='}'){
34                 if(stack.isNull()){
35                     return false;//棧為空,匹配失敗
36                 }else if(stack.pop()=='{'){
37                     continue;//匹配成功繼續下一次循環
38                 }else{
39                     return false;//匹配不成功代表該表達式不符合規則
40                 }
41             }
42         }
43         //如果最后沒有右括號但是還存在左括號表示不匹配
44         return stack.isNull();  
45     }  
46 
47 }
isMatch

  測試:

 1 package test;
 2 
 3 import org.junit.Test;
 4 
 5 public class test {
 6     @Test
 7     public void fun(){
 8         String str1 = "i((l)o[v{e}]y)o{u}!";//表達式1:(()[{}]){}
 9         String str2 = "you((do)[not{}])know{}!)";//表達式2:(()[{}]){})
10         boolean match1 = StackUtils.isMatch(str1);
11         boolean match2 = StackUtils.isMatch(str2);
12         System.out.println("str1中的括號是否匹配:"+match1);
13         System.out.println("str2中的括號是否匹配:"+match2);
14     }
15 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM