1. 程式人生 > >Java陣列實現迴圈佇列

Java陣列實現迴圈佇列

Java陣列實現迴圈佇列

上一節(Java實現佇列——順序佇列、鏈式佇列)我們使用陣列實現了順序佇列,但是在tail == n時會有資料搬移操作,這樣入隊操作效能就會受到影響。這裡我們使用迴圈佇列的解決思路。

迴圈佇列

顧名思義,首尾相連就形成了迴圈佇列,如下圖所示:

實現迴圈佇列最關鍵的部分是確定佇列何時為空何時滿。在用陣列實現的非迴圈佇列中,隊滿的判斷條件是tail == n,隊空的判斷條件是head == tail。在迴圈佇列中,佇列為空的判斷條件仍然是head == tail,但佇列滿的判斷條件有所更改,是( tail + 1 ) % capacity == head


另外一點需要注意的是,當佇列滿時,tail指標指向的位置實際上是沒有儲存資料的,所以會浪費一個數組的儲存空間。

程式碼實現如下:

public class CircularQueue implements QueueInterface {
    private String[] values;// 容器
    private int capacity = 0;// 容量
    // head 表示隊頭下標,tail表示對尾下標
    private int head = 0;
    private int tail = 0;

    public CircularQueue(int capacity) {
        values = new String[capacity];
        this.capacity = capacity;
    }

    @Override
    public Boolean enqueue(String value) {
        // 佇列滿了
        if ((tail + 1) % capacity == head) {
            return false;
        }
        values[tail] = value;
        tail = (tail + 1) % capacity;
        return true;
    }

    @Override
    public String dequeue() {
        // 如果head == tail 表示佇列為空
        if (head == tail) {
            return null;
        }
        String ret = values[head];
        head = (head + 1) % capacity;
        return ret;
    }

    @Override
    public String toString() {
        return "CircularQueue{" +
                "values=" + Arrays.toString(values) +
                ", capacity=" + capacity +
                ", head=" + head +
                ", tail=" + tail +
                '}';
    }
}

測試程式碼:

    CircularQueue cq = new CircularQueue(10);
    System.out.println(cq);
    System.out.println();

    //正常新增的資料
    System.out.println("正常新增的資料:");
    for (int i = 0; i < 9; i++) {
        System.out.println("cq.enqueue():" + cq.enqueue("" + i + i + i));
        System.out.println(cq);
    }
    System.out.println();

    // 佇列滿了以後新增資料
    System.out.println("佇列滿了以後新增資料:");
    System.out.println("cq.enqueue():" + cq.enqueue("aaa"));
    System.out.println(cq);
    System.out.println();

    // 清空佇列
    System.out.println("清空佇列:");
    for (int i = 0; i < 9; i++) {
        System.out.println("cq.dequeue():" + cq.dequeue());
        System.out.println(cq);
    }
    System.out.println();

    // 佇列清空以後,繼續清空
    System.out.println("佇列清空以後,繼續清空:");
    System.out.println("cq.dequeue():" + cq.dequeue());
    System.out.println(cq);

輸出結果:符合期望

CircularQueue{values=[null, null, null, null, null, null, null, null, null, null], capacity=10, head=0, tail=0}

正常新增的資料:
cq.enqueue():true
CircularQueue{values=[000, null, null, null, null, null, null, null, null, null], capacity=10, head=0, tail=1}
cq.enqueue():true
CircularQueue{values=[000, 111, null, null, null, null, null, null, null, null], capacity=10, head=0, tail=2}
cq.enqueue():true
CircularQueue{values=[000, 111, 222, null, null, null, null, null, null, null], capacity=10, head=0, tail=3}
cq.enqueue():true
CircularQueue{values=[000, 111, 222, 333, null, null, null, null, null, null], capacity=10, head=0, tail=4}
cq.enqueue():true
CircularQueue{values=[000, 111, 222, 333, 444, null, null, null, null, null], capacity=10, head=0, tail=5}
cq.enqueue():true
CircularQueue{values=[000, 111, 222, 333, 444, 555, null, null, null, null], capacity=10, head=0, tail=6}
cq.enqueue():true
CircularQueue{values=[000, 111, 222, 333, 444, 555, 666, null, null, null], capacity=10, head=0, tail=7}
cq.enqueue():true
CircularQueue{values=[000, 111, 222, 333, 444, 555, 666, 777, null, null], capacity=10, head=0, tail=8}
cq.enqueue():true
CircularQueue{values=[000, 111, 222, 333, 444, 555, 666, 777, 888, null], capacity=10, head=0, tail=9}

佇列滿了以後新增資料:
cq.enqueue():false
CircularQueue{values=[000, 111, 222, 333, 444, 555, 666, 777, 888, null], capacity=10, head=0, tail=9}

清空佇列:
cq.dequeue():000
CircularQueue{values=[000, 111, 222, 333, 444, 555, 666, 777, 888, null], capacity=10, head=1, tail=9}
cq.dequeue():111
CircularQueue{values=[000, 111, 222, 333, 444, 555, 666, 777, 888, null], capacity=10, head=2, tail=9}
cq.dequeue():222
CircularQueue{values=[000, 111, 222, 333, 444, 555, 666, 777, 888, null], capacity=10, head=3, tail=9}
cq.dequeue():333
CircularQueue{values=[000, 111, 222, 333, 444, 555, 666, 777, 888, null], capacity=10, head=4, tail=9}
cq.dequeue():444
CircularQueue{values=[000, 111, 222, 333, 444, 555, 666, 777, 888, null], capacity=10, head=5, tail=9}
cq.dequeue():555
CircularQueue{values=[000, 111, 222, 333, 444, 555, 666, 777, 888, null], capacity=10, head=6, tail=9}
cq.dequeue():666
CircularQueue{values=[000, 111, 222, 333, 444, 555, 666, 777, 888, null], capacity=10, head=7, tail=9}
cq.dequeue():777
CircularQueue{values=[000, 111, 222, 333, 444, 555, 666, 777, 888, null], capacity=10, head=8, tail=9}
cq.dequeue():888
CircularQueue{values=[000, 111, 222, 333, 444, 555, 666, 777, 888, null], capacity=10, head=9, tail=9}

佇列清空以後,繼續清空:
cq.dequeue():null
CircularQueue{values=[000, 111, 222, 333, 444, 555, 666, 777, 888, null], capacity=10, head=9, tail=9}

完整程式碼請檢視

專案中搜索SingleLinkedList即可。
github傳送門 https://github.com/tinyvampirepudge/DataStructureDemo

gitee傳送門 https://gitee.com/tinytongtong/DataStructureDemo

參考:
佇列:佇列線上程池等有限資源池中的應用