ホームページ  >  記事  >  Java  >  Javaは循環キューを実装します

Javaは循環キューを実装します

王林
王林転載
2019-12-31 17:14:382886ブラウズ

Javaは循環キューを実装します

循環キューの利点

通常のキューのデキュー操作は高価です。デキュー操作中、インデックス 0 以降のすべての要素を移動する必要があります。要素が多いほど、より多くの時間が消費され、時間計算量は O(N) になります。

循環キューのロジック:

1. 要素が少ない場合 (末尾の位置が先頭の後ろにある場合)、循環キューは同じキューイング操作を行います。通常のキューと同様に、キューの要素は末尾の位置に配置され、末尾の操作が実行されます。要素がデキューされると、先頭の位置にある要素は null に設定され、その後、先頭の操作が実行されます。

Javaは循環キューを実装します

#2. 図に示すように、このとき、末尾の位置は前部の後ろに維持することができます。追加すると、最後の要素はインデックス 7 に配置されます。このとき、末尾の位置はキューの先頭のインデックスの前に移動します。位置 0 では、配列内の末尾のインデックスは次のようになります。(tail 1) 以下の図に示す容量%:

Javaは循環キューを実装します

3. 要素が追加され続けると、要素は末尾の位置に追加され、末尾が続きます。次の図に示すように、後方に移動します:

Javaは循環キューを実装します

#4. 後部と前部がまだ 1 単位離れているときに、要素を追加し続けます。 、配列にはまだ空き記憶領域がありますが、現在の配列では循環キューの挿入操作を実装できなくなりました。これは、循環キューがキューが空であると判断するための条件が前 == 末尾であるため、拡張現時点では操作が必要なので、ここでは意識的にスペースを無駄にしています。

ここで、循環キュー要素が満杯になるための条件は次のとおりであると推測できます: 末尾 1 == フロント (暫定的な結論。(末尾 1) % 容量 == フロントに改善されます)

5 . 適切な状況下で、デキュー操作が継続すると、フロントの位置も配列の右端から配列の左端にジャンプします。このとき、配列内のフロントのインデックスは次のようになります: (フロント 1)% 容量

コード実装: (関連ビデオ チュートリアルの共有: java ビデオ チュートリアル

)

package dataStructure.chapter3;

/**
 * @Author: zjtMeng
 * @Date: 2019/12/28 20:13
 * @Version 1.0
 */
public class LoopQueue<E> implements Queue<E> {

    private E[] data;
    private int front,tail;
    private int size;

    public LoopQueue(int capacity){
        data = (E[]) new Object[capacity+1];
    }

    public LoopQueue(){
        this(10);
    }

    public int getCapacity(){
        return data.length-1;
    }

    /**
     * 循环队列入队操作
     * @param e
     */
    @Override
    public void enqueue(E e) {
        //循环队列元素满的判断条件,如果满了就进行扩容操作,扩大两倍
        if ((tail+1)%data.length == front)
            resize(2 * getCapacity());
        data[tail] = e;
        tail = (tail + 1) % data.length;
        size ++;

    }

    /**
     * 循环队列扩容
     * @param newCapacity
     */
    private void resize(int newCapacity){
        E[] newData = (E[]) new Object[newCapacity+1];
        //循环队列第一种遍历方式
        for (int i = 0 ; i < size ; i++ ){
//newData[]中的元素与data[]中的元素,一方面存在着front的偏移量,另一方面,data[]中的元素,
//可能在有部分处于front前面,因此此处采用对数组长度取余,来判断元素的位置
            newData[i] = data[(i+front)%data.length];
        }
        data = newData;
        front =0;
        tail = size;

    }

    @Override
    public E dequeue() {
        //首先判断队列是否为空,如果为空则抛出异常
        if (isEmpty())
            throw new IllegalArgumentException("Cannot dequeue from an empty queue.");
        E ret = data[front];
        //引用地址需要置空,否则JVM不能及时回收空间,从而可能会出现OOM异常
        data[front] = null;
        front = (front + 1 )% data.length;
        size--;
        //如果元素数量达到队列容积的1/4,且队列容积/2 不等于0时,进行缩容操作
        if (size == getCapacity() / 4 && getCapacity() / 2 != 0 )
            resize(getCapacity() / 2);
        return ret;
    }

    /**
     * 查看队首元素
     * @return
     */
    @Override
    public E getFront() {
        if (isEmpty())
            throw new IllegalArgumentException("Queue is empty.");
        return data[front];
    }

    @Override
    public int getSize() {
        return size;
    }

    /**
     * 判断循队列是否为空
     * @return
     */
    @Override
    public boolean isEmpty() {
        return front == tail;
    }

    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
        res.append(String.format("Queue: size = %d, capacity = %d\n",size, getCapacity()));
        res.append("front[");
        //循环队列遍历的第二种方法
        for (int i = front; i != tail; i = (i + 1) % data.length){
            res.append(data[i]);
            //循环队列未遍历到队尾的标志
            if ((i + 1) % data.length != tail)
                res.append(", ");
        }
        res.append("] tail");
        return res.toString();
    }
}
おすすめの関連記事とチュートリアル: Java 入門チュートリアル

###

以上がJavaは循環キューを実装しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。