循環キューの利点
通常のキューのデキュー操作は高価です。デキュー操作中、インデックス 0 以降のすべての要素を移動する必要があります。要素が多いほど、より多くの時間が消費され、時間計算量は O(N) になります。
循環キューのロジック:
1. 要素が少ない場合 (末尾の位置が先頭の後ろにある場合)、循環キューは同じキューイング操作を行います。通常のキューと同様に、キューの要素は末尾の位置に配置され、末尾の操作が実行されます。要素がデキューされると、先頭の位置にある要素は null に設定され、その後、先頭の操作が実行されます。
#2. 図に示すように、このとき、末尾の位置は前部の後ろに維持することができます。追加すると、最後の要素はインデックス 7 に配置されます。このとき、末尾の位置はキューの先頭のインデックスの前に移動します。位置 0 では、配列内の末尾のインデックスは次のようになります。(tail 1) 以下の図に示す容量%: 3. 要素が追加され続けると、要素は末尾の位置に追加され、末尾が続きます。次の図に示すように、後方に移動します: #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は循環キューを実装しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。