棧——鏈棧和數組棧(Java)

  棧(stack)又名堆棧,它是一種運算受限的線性表。限定僅在表尾進行插入和刪除操作的線性表。這一端被稱爲棧頂,相對地,把另一端稱爲棧底。向一個棧插入新元素又稱作進棧、入棧或壓棧,它是把新元素放到棧頂元素的上面,使之成爲新的棧頂元素;從一個棧刪除元素又稱作出棧或退棧,它是把棧頂元素刪除掉,使其相鄰的元素成爲新的棧頂元素。棧最大的特點就是先進後出

上面是棧存取數據的示意圖,棧主要分爲兩種結構:基於數組實現的數組棧和基於鏈表實現的鏈棧,總的來說都是棧結構,實現的都是棧的基本操作,而棧的操作需要具體的結構去實現,因此數組棧和鏈棧都是實現的棧接口,我們先定義一個棧接口:

interface Stack {
    public abstract void push(int e);  //入棧操作
    public abstract int pop();    //彈棧
    public abstract int length();  //有效元素個數
    public abstract boolean isEmpty(); //判空操作
}

數組棧/順序棧:由數組實現的,但是不提供角標的訪問,只在棧頂進行操作。

/*
基於數組實現的棧
*/
class ArrayStack implements Stack{
    private static int DEFAULT_SIZE=10; //默認容量
    private int top;    //棧頂指針
    private int[] data; //存儲元素的容器用數組存儲
    //創建一個棧使用默認容量
    public ArrayStack(){
        this(DEFAULT_SIZE);
    }
    //創建一個棧使用用戶指定容量capacity
    public ArrayStack(int capacity){
        super();
        this.top=-1; //初始化棧頂元素
        this.data=new int[capacity]; //初始化容量
    }
    //入棧一個元素e
    public void push(int e){ 
        if(top==data.length-1){  //入棧前要判滿,如果棧頂指針達到容量最大,表示無法入棧
            System.out.println("棧已滿!無法入棧元素");
        }
        data[++top]=e; //否則先將棧頂指針先向上移動一個,將元素添加到該指針位置
    }
      //出棧一個元素
    public int pop(){
        if(isEmpty()){ //出棧前先判空
            System.out.println("棧已空!無法出棧元素");  //棧內爲空,沒有元素
            return -1;//特殊含義 表示錯誤
        }
        return data[top--];  //棧不爲空,先將元素彈棧,再將棧頂指針下移
    }
    //判斷棧是否爲空
    public boolean isEmpty(){  
        return this.top==-1; //如果當前棧頂元素爲空,爲true否則爲false
    }
    //獲取有效元素的個數
    public int length(){
        return this.top+1;  //獲取當前棧頂指針加一,因爲是用數組實現的
    }
    public String toString(){  //以字符串形式打印當前棧內元素
        StringBuilder sb=new StringBuilder(); 
        sb.append('[');
        for(int i=0;i<=top;i++){
            sb.append(data[i]);
            if(i==top)
                return sb.append(']').toString();
            sb.append(',');
            sb.append(' ');
        }
        return "[]";
    }
    //獲取當前棧的總容量
    public int getCapacity(){
        return data.length;  //總容量就是數組的大小
    }
}

鏈棧,是由鏈表實現的,鏈表由一系列結點(鏈表中每一個元素稱爲結點)組成,每個結點包括兩個部分:一個是存儲數據元素的數據域,另一個是存儲下一個結點地址的指針域。 相比於線性表順序結構,操作複雜。由於不必須按順序存儲,鏈表在插入的時候可以達到O(1)的複雜度,比另一種線性表順序錶快得多,但是查找一個節點或者訪問特定編號的節點則需要O(n)的時間,而線性表和順序表相應的時間複雜度分別是O(logn)和O(1)。這裏是鏈棧結構,則存取完全可以根據棧結構對頭結點進行操作。

class LinkedStack extends Stack{   //單向鏈表
    private Node head;      //鏈表的頭結點
    private int size;      //鏈表長度
    public LinkedStack(){ 
        this.head=new Node();
        this.size=0;
    }
 
     //加入結點是不用判滿的,因爲鏈表沒有容量限制
    public void push(int e){  //在頭結點後添加一個新的元素結點
        Node n=new Node(); //新創建一個結點
        n.data=e;  //將創建的結點中的數據域用來存放傳入的元素
        n.next=head.next; //將創建的結點中的指針域用來存放當前頭結點的下一個結點的地址
        head.next=n;  //然後將新創建的結點的地址賦給頭結點的指針域
        //head.next=new Node(e,head.next); 上面三行代碼可簡化成這一句
        size++; //鏈表長度加一
    }
    public int pop(){   //元素出棧
        if(isEmpty()){  //出棧判空
            System.out.println("棧已空!不能出棧元素!");
            return -1;
        }
        Node n=head.next;  //元素不爲空,將頭元素的下一個元素提取出來
        head.next=n.next;    //將頭元素下一個結點的下一個結點的地址賦給頭元素的指針域
        n.next=null;   //將頭元素的下一個結點的指針域置爲null,與原鏈表斷離
        size--;      //相應的鏈表長度減一
        return n.data;   //將刪除的結點的數據返回
    }
    public int length(){  //獲取鏈表的長度
        return size;   //直接返回size,因爲這個變量記錄了鏈表的長度
    }
    public boolean isEmpty(){  //判空
        return size==0&&head.next==null;  //如果鏈表長度爲0和頭結點的後面沒有其他結點,則爲空
    }
    public String toString(){  //獲取鏈表得字符串形式輸出
        if(isEmpty()){
            return "[]";
        }
        Node p=head.next;  //定義一個結點變量存放頭結點的下一個結點的地址
        StringBuilder sb=new StringBuilder();
        sb.append('[');
        while(true){
            sb.append(p.data); //將該結點的數據域添加到字符串中
            if(p.next==null){
                sb.append(']');
                break;
            }else{
                sb.append(", ");
                p=p.next;  //再將下一個結點的地址賦給當前結點變量
            }
        }
        return sb.toString();
    }

    //內部類:在類裏面定義的類
    private class Node{   //結點類
        int data;   //數據域
        Node next;   //指針域
        Node(){
            this(0,null);
        }
        Node(int data,Node next){  //帶參的構造函數
            this.data=data;   
            this.next=next;
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章