この記事では、ビデオチュートリアル「高度なデータ構造へのエントリから楽しい」の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);
}
}
}