サイクルキュー配列「の楽しみは、エントリからのデータ構造を高度な」

この記事では、ビデオチュートリアル「高度なデータ構造へのエントリから楽しい」のliuyuboboboから来ています

キューは、特別な直線状であることが唯一の挿入動作テーブルの後端部が、テーブルの前端部に欠失を可能にするという点で特別です。端の後端と呼ぶ、削除操作は、ヘッドの挿入操作と呼ぶことにします。

我々は、配列のキューを使用すると仮定し、以下を参照してください

エンキュー操作は非常に速く、あなただけの尾部に要素を追加する必要があります。しかし、呼び出し元に削除と復帰後の時間がかかり、ヘッド素子上で動作チームは、アレイ内のすべての要素を配置する必要が前進するために、このステップは非常に時間がかかるです。

デキューA、B、Cの後に、Dは、標識された下方位置に移動させる0,1,2

チームを行う方法がある場合、配列の要素は、それを移動しないのですか?滴は、ループ配列を使用して、あります

循環キューは、いくつかの機能があります。

図1に示すように、フロント可変ポイントHOL(全ての要素)、テイル(元素)にテール可変ポイント。

(;後膨張を話すこのステートメントは正確な定義が与えられ、続いて、次いで、完全に正しくない「戻る」)前後チーム移動添字2、

それは尾に追加された要素であった3、尾部を移動させ、後方Aの添字

図4に示すように、フロント==テールキューが満杯である、キューが空であることを示していないフロント、尾部は、同一の要素を指すが、尾部の前方位置の手前です。

図は、要素が空になるように、尾ポインティング要素キューが満杯である場合、アレイ8の長さが、唯一のストアキュー素子7です。

キューが空であり、それはときにも、フロント==テールは、キューが空の場合を区別するためのコードの実装に、キューが満杯であり、それはあなたがして、メモリアレイのフロント==尾を実行する必要がある場合、低下させることで複雑。テールキューが空であるだけでメモリ素子を「無駄」、フロントは==、これは1例のみです。

判定条件がある場合5は、(図8の配列の長さ)data.length定義配列の長さは、キューが満杯である  フロントdata.length%の(+尾1)==、我々は図の良好な状態を輝く決意を理解します。

図6に示すように、チームは、ある移動可能尾尾=(尾+ 1)%のdata.length

     デキュー、フロント移動は、前面=(フロント+ 1)%のdata.lengthであります

図の例で支出

エンキュー操作、尾=(1 + 1)%8 = 2,2に尾

デキュー操作、フロント=(3 + 1)%8 = 4、フロント4となります

前方位置添字7とき前方位置、デキュー、fornt =この時点で(7 + 1)%8 = 0、0

図7以下、拡張、。条件を満たす(尾+ 1)%data.length ==フロント、容量は、現時点では必要とされています

次のようにコードがあります

// 基于循环数组实现队列
public class LoopQueue<E>{
    private E[] data;  // 数组
    private int front, tail;  //队头、队尾
    private int size;  //队列元素大小

    public LoopQueue(){
        data = (E[]) new Object[11];  //初始化队列的数组
        // 初始化时队头、队尾下标都为0,队列大小也是0
        front = 0;
        tail = 0;
        size = 0;
    }

    // 队列容量是数组长度减1,因为要空一个元素,以便区别队列是否为空、队列是否满了需要扩容
    public int getCapacity(){
        return data.length -1;
    }

    //队列为空
    public boolean isEmpty(){
        return front == tail;
    }

    //队列大小
    public int getSize(){
        return size;
    }

    //扩容、缩容
    private void resize(int newCapacity){
        // 数组长度要比容量多一个
        E[] newData = (E[])new Object[newCapacity+1];
        //将旧数据从队头开始,添加到新数组中
        for (int i=0; i<size; i++){
            newData[i] = data[(i+front) % data.length];
        }
        front = 0;  //添加完成,队头在新数组下标为0的位置
        tail = size;  //添加完成,队列大小就是队尾的下标
        data = newData;  //队列的数组data指向扩容后的数组
    }

    //入队
    public void enqueue(E e){
        //如果队列满了,则扩容
        if ((tail + 1) % data.length == front){
            resize(getCapacity() * 2);
        }
        data[tail] = e;
        //队尾下标移动
        tail = (tail + 1) % data.length;
        //队列大小加一
        size++;
    }

    //出队
    public E dequeue(){
        if (isEmpty())
            throw new RuntimeException("没数据了");
        //队头数据存储到变量中
        E ret = data[front];
        data[front] = null;
        //队头下标移动
        front = (front + 1) % data.length;
        //队列大小减一
        size--;

        //这是缩容,如果队列大小小于容量的1/4且容量的1/2不为0,队列缩容为原来的1/2
        if (size < getCapacity()/4 && getCapacity()/2 != 0){
            resize(getCapacity()/2);
        }
        //返回队头数据
        return ret;
    }



    @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();
    }

    public static void main(String[] args){

        _2_LoopQueue.LoopQueue<Integer> queue = new _2_LoopQueue.LoopQueue<>();
        for(int i = 0 ; i < 20 ; i ++){
            queue.enqueue(i);
            System.out.println(queue);

            if(i % 10 == 0){
                queue.dequeue();
                System.out.println(queue);
            }
        }
        for(int i = 0 ; i < 18 ; i ++){
            queue.dequeue();
            System.out.println(queue);
        }
    }

}

 

公開された51元の記事 ウォン称賛14 ビュー40000 +

おすすめ

転載: blog.csdn.net/u010606397/article/details/98173224