淺談棧和隊列

### 棧

棧模型

棧(stack)是限制對元素的插入(push)和刪除(pop)只能在一個位置上進行的表,該位置是表的末端,叫作棧的棧頂(top)。html

棧的基本操做只有兩種,壓入棧(push)和彈出棧頂(pop),且只能做用於棧頂。(只有棧頂元素是可訪問的前端

你能夠把棧結構理解成一個底部封閉,頂部打開的桶。最早進去的元素必定是最後才能取出,最晚進去的元素必定是最早取出。
所以棧又叫作LIFO(後進先出,Last In First Out)表。java

棧的優點

棧的操做是常數時間的,並且是以很是快的常數時間。在某些機器上,push和pop均可以寫成一條機器指令,現代計算機把棧操做做爲它指令的一部分。所以棧是在計算機科學中繼數組以後最基本的數據結構。node

棧的實現

棧的實現分爲數組實現和鏈表實現。編程

1` 鏈表實現
這裏咱們使用單鏈表來實現,定義一個first指針指向棧頂,棧的鏈表實現其實是簡化了單鏈表實現,具體實現看如下代碼。後端

public class StackImplementByLinklist<AnyType> {
    public Node<AnyType> first;
    int size;
    //內部類定義node
    public class Node<AnyType>{
        AnyType data;
        Node<AnyType> next;
    }
     //初始化
    public void stack(){
        first=null;
        size=0;
    }

    public void push(AnyType a){
        Node oldNode=first;
        first=new Node();
        first.data=a;
        first.next=oldNode;
        size++;
    }

    public AnyType pop(){
        AnyType a=first.data;
        first=first.next;
        size--;
        return a;
    }

    public boolean isEmpty(){
        return size==0;
    }

    public int size(){
        return size;
    }
}

2` 數組實現
相比於鏈表實現,數組實現棧更加的經常使用。由於數組操做的常數時間極短,並且實現起來更加簡單。數組

public class StackImplementByArray<AnyType> {
    AnyType[] arr;
    int size;
    public void stack(int capacity){
        arr=(AnyType[])new Object[capacity];
        size=0;

    }
    public void push(AnyType a){
        if(size==arr.length){
            changeArray(2*size+1);
        }
        arr[size]=a;
        size++;
    }
    public AnyType pop(){
        if(size==0){
            System.out.println("棧頂爲空");
            System.exit(0);
        }
        AnyType a=arr[size-1];
        arr[size-1]=null;
        size--;
        return a;
    }
    public boolean isEmpty(){
        return size==0;
    }
    public int size(){
        return size;
    }

    //因爲數組大小是要先肯定的,所以當數組滿了後要擴大數組容量
    public void changeArray(int newCapacity){
        AnyType[] newArr=(AnyType[])new Object[newCapacity];
        for(int i=0;i<arr.length;i++){
            newArr[i]=arr[i];
        }
        arr=newArr;
    }

}

棧的應用

  • 平衡符號的檢測數據結構

    編譯器檢查程序符號的語法錯誤,經常就是經過棧來實現的。this

在編程時,咱們常常會用到「 ( ),[ ],{ }," " 」這些符號,當這些符號不是配對出現的,編譯器就會報錯,編譯就沒法經過。指針

那麼,編譯器是怎麼知道這些符號有沒有配對出現的呢?它一般是這麼處理的。

當遇到左符號,如「( [ { " 」這些,就把它壓入一個準備好的棧;不然就彈出棧頂,檢測當前符號是否與棧頂元素配對。一旦不能配對,直接退出報錯。


### 隊列

隊列模型

wiki: 隊列,又稱爲佇列(queue),是先進先出(FIFO, First-In-First-Out)的線性表。在具體應用中一般用鏈表或者數組來實現。隊列只容許在後端(稱爲rear)進行插入操做,在前端(稱爲front)進行刪除操做。隊列的操做方式和堆棧相似,惟一的區別在於隊列只容許新數據在後端進行添加。

隊列模型就至關於咱們平常生活的排隊,在隊伍的後面入隊,在隊伍的前端出隊。

多種隊列

隊列通常分爲普通的數組隊列,鏈表隊列和循環隊列。

鏈表隊列:長度通常是無限的,通常不存在溢出的可能性,用完就銷燬,不會浪費內存空間。

普通的數組隊列:長度通常是有限的,即數組長度。因爲元素出隊後其位置的內存空間並不會釋放,所以會浪費大量的內存空間。

循環隊列:特殊的數組隊列,因爲普通的數組的隊列會浪費大量的內存空間,所以出現了循環隊列。當循環隊列的隊尾指針到達數組末尾後,會從新回到數組起始位置,實現了對內存的重複利用。

隊列的實現

1` 鏈表隊列

public class QueueImplementByLinkList<AnyType> {
    Node first;//隊首
    Node last;//隊尾
    int size;
    public class Node{
        AnyType data;
        Node next;
        public Node(AnyType data,Node next){
            this.data=data;
            this.next=next;
        }
    }
    
    //初始化隊列
    public void initqueue(){
        first=new Node(null,null);
        last=first;
        size=0;
    }

    //入隊
    public void enqueue(AnyType a){
        if(size==0){
            last.data=a;
            size++;
            return;
        }
        Node oldlast=last;
        last=new Node(a,null);
        oldlast.next=last;
        size++;
    }

    //出隊
    public AnyType dequeue(){
        if(size==0){
            System.out.print("隊列爲空");
            System.exit(0);
        }
        AnyType a=first.data;
        first=first.next;
        size--;
        return a;
    }
    public boolean isEmpty(){
        return size==0;
    }
    public int size(){
        return size;
    }
}

2` 數組隊列

public class QueueImplementByArray<AnyType> {
    AnyType[] arr;
    int first;
    int last;
    int size;
    //初始化
    public void ininqueue(int capacity){
        arr=(AnyType[])new Object[capacity];
        first=0;
        last=0;
        size=0;
    }
    public void enqueue(AnyType a){
        if(size==arr.length){
            changeArray(2*size+1);
        }
        arr[last++]=a;
        size++;
    }
    public AnyType dequeue(){
        if(size==0){
            System.out.println("隊列爲空");
            System.exit(0);
        }
        AnyType a=arr[first++];
        arr[first-1]=null;
        size--;
        return a;
    }
    public void changeArray(int newCapacity){
        AnyType[] newArr=(AnyType[])new Object[newCapacity];
        for(int i=0;i<arr.length;i++){
            newArr[i]=arr[i];
        }
        arr=newArr;
    }
    public boolean isEmpty(){
        return size==0;
    }
    public int size(){
        return size;
    }

}

3` 循環隊列

public class CycleQueue {
    int[] arr;
    int start;//隊首
    int end;//隊尾
    int size=0;
    //初始化
    public void initqueue(int size){
        arr=new int[size];
        size=0;
        start=0;
        end=0;
    }

    //入隊
    public void enqueue(int num){
        if(size>arr.length){
            System.out.println("隊列已滿");
            return;
        }
        if(end==arr.length){
            end=0;
        }
        arr[end++]=num;
        size++;
    }

    //出隊
    public int dequeue(){
        if(size==0){
            System.out.println("隊列爲空");
            System.exit(0);
        }
        if(start==arr.length){
            start=0;
        }
        size--;
        return arr[start++];
    }

    public boolean isEmpty(){
        return size==0;
    }
    public int size(){
        return size;
    }
}

一點點總結

棧和隊列是基本的數據結構,是對數組和鏈表的從新封裝和擴展。因爲它們的特性和執行速度,棧和隊列被普遍的使用。

最後,不要爲了使用數據結構而使用使用數據結構,要區分各類數據結構的使用場景,靈活地運用數據結構,能夠事半功倍。

若是這篇文章對你有幫助的話,左下角給個推薦鴨,這個對我真的很重要,qiu'qiu。😄

相關文章
相關標籤/搜索