棧和隊列


棧:先進后出(底層用數組實現)

 只有一個開口,先進去的就到最底下,后進來的就在前面,要是拿出去的話,肯定是從開口端拿出去,
 所以說先進后出,后進先出。

數據結構:

java實現棧(基於數組):

/**
 * 棧只有一個開口,先進去的就到最底下,后進來的就在前面,要是拿出去的話,肯定是從開口端拿出去,
 * 所以說先進后出,后進先出。
 */
public class MyStack {
    //底層實現是一個數組
    private long[] arr;
    /**
     * 最上層的一個指針 棧頂
     */
    private int top;
    /**
     * 默認的構造方法
     */
    public MyStack(){
        arr = new long[10];
        top=-1;
    }
    /**
     * 增加數據 先把指針加一
     * 然后指針指向最新的數據
     */
    public void push(int value){
        //top++是top先不自加,在語句完后自加。| ++top先自加 然后使用top的值
        arr[++top] = value;
    }
    
    /**
     * 移除數據 先把最頂層指針執行的數據return 然后指針減一
     */
    public long pop(){
        //--top 是先執行top=top-1,然后再使用top的值 | top-- 是先使用top的值 然后 在執行top=top-1
        return arr[top--];
    }
    
    public static void main(String[] args) {
        MyStack myStack = new MyStack();
        myStack.push(1);
        myStack.push(2);
        myStack.push(3);
        System.out.println(myStack.pop());
    }
}

main()方法中 3是最后push()進去 是最先pop()出來,先進后出,后進先出。

隊列:先進先出(底層用數組實現)

隊列有隊頭(front)和隊尾(end),數據從隊尾進入隊列,從隊頭出隊列,隊頭(front)指向隊列的第一個數據,隊尾(end)指向隊列中的最后一個數據。

隊列的數據結構

java實現隊列(基於數組)

package javaee.net.cn.tree.ch10;

public class MyQueue {
    //底層使用數組
    private long[] arr;
    //隊頭
    private int front;
    //隊尾
    private int end;
    
    /**
     * 默認構造方法
     */
    public MyQueue(){
        arr = new long[10];
        front=0;
        end = -1;
    }
    /**
     * 添加數據 從隊尾插入
     */
    public void insert(long value){
        arr[++end] = value;
    }
    /**
     * 刪除數據,從隊頭刪除
     */
    public long remove(){
        return arr[front++];
    }
    
    public static void main(String[] args) {
        MyQueue myQueue = new MyQueue();
        myQueue.insert(1L);
        myQueue.insert(2L);
        System.out.println(myQueue.remove());
    }
}

main()方法中 1是先insert()進去 也是先remove()出來,所以說 先進先出。

鏈表實現隊列

JDK中的LinkedList(底層用鏈表實現)

以上隊列是以數組來模擬(比較簡單),JDK API中的Queue隊列底層是以鏈表來實現的。

LinkedList 類實現了Deque(雙端隊列)接口 並且具有

addFirst()  addLast()  getFirst() getLast() removeFirst() removeLast() 方法

使得LinkList可以作為 棧 隊列 雙向隊列使用

至於LinkedList的實現原理,在這就不做多敘述了 大家可以參考API

鏈表

上面的棧和隊列都是以數組模擬實現,但是JDK中LinkedList底層是鏈表實現的,現在我們看看什么是鏈表

鏈表是由一個個的節點構成的,節點(Node)分為兩個部分,第一個部分(data)保存或者顯示關於節點的信息,另一個部分存儲下一個節點的地址。

鏈表最后一個節點存儲地址的部分指向空值。

節點Node:

/**
 * 連接點 相當於是車廂
 */
public class Node {
    //數據域 保存數據
    public long data;
    
    //指針域 保存下一個節點的引用
    public Node next;
    
    public Node(long value){
        this.data=value;
    }
}

而插入一個節點,對於單向鏈表,我們只提供在鏈表頭插入,只需要將next指向原頭節點,當前插入的節點設置為頭節點即可。

    /**
     * 插入一個節點,在頭結點進行插入
     */
    public void insertFirst(long value){
        Node node = new Node(value);
        node.next=first;
        first=node;
    }

刪除一個節點,我們將該節點的上一個節點的next指向該節點的下一個節點。

如果被刪除的是頭結點,直接將頭節點的下一個節點,賦值給頭節點

    /**
     * 刪除方法 根據數據域進行刪除
     */
    public Node delete(long value){
        Node current = first;
        Node pre = null;
        while(current.data!=value){
            if(current.next==null){
                return null;
            }
            pre = current;
            current= current.next;
        }
        if(current == first){
            first = first.next;
        }else{
            pre.next=current.next;
        }
        return current;
    }

BlockingQueue

普通的隊列沒有考慮線程之間的同步,當多個線程操作同一個隊列時,會導致並發問題。

BlockingQueue接口繼承了Queue接口,BlockingQueue接口為多個線程操作同一個隊列提供了四種處理方案(,對於不能立即滿足但可能在將來某一時刻可以滿足的操作)

  拋出異常 特殊值 阻塞 超時
插入 add(e) offer(e) put(e) offer(e, time, unit)
移除 remove() poll() take() poll(time, unit)
檢查 element() peek() 不可用 不可用

其中方案一和方案二來自Queue接口,方案三和方案四是在BlockingQueue接口中新增的。

比如線程阻塞:

在通過put(e)方法向隊列尾部添加元素時,如果隊列已滿,則當前線程進入阻塞狀態,直到隊列有剩余容量來添加元素,才退出阻塞。

在通過take()方法從隊列頭部刪除並返回元素時,如果隊列為空,則當前線程進入阻塞狀態,直到從隊列中成功刪除並返回元素為止。

在java.util.concurrent包中 BlockingQueue接口主要有以下實現類

LinkedBlockingQueue

ArrayBlockingQueue

PriorityBlockingQueue

DelayQueue


免責聲明!

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



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