您的位置:首页 > 其它

队列--数组实现

2016-08-02 11:23 155 查看
  可以仿照利用数组实现栈的过程,使用数组实现队列。以front指向队首元素,值始终为数组首元素a[0]。出队时,front保持不变,删除队首元素,其余元素依次向前移动,时间复杂度是O(n)。入队时,根据队列大小将元素存储到相应位置。上述实现因为不断移动元素,效率太低。因此以下使用环形数组的形式来构造队列。定义两个变量:

front:指向队首元素。

rear:指向队尾元素的下一个位置。
另外设环形数组大小为len。初始状态下,front=rear=0。入队时,在rear指向的位置存储元素,然后令rear=(rear+1)%len。出队时,删除front指向的元素,然后令front=(front+1)%len。最后,front=rear既是队满的判断条件又是队空的判断条件,不过可以完美解决。在入队方法enqueue中,size==CAPACITY,那么就是队满了。在出队方法中,如果size==0,那么即使队空了。不过这种方法会导致原有队首元素被覆盖(覆盖原队首元素不符合队列的设计初衷),可以通过禁止队列规模超过CAPACITY-1的方法来解决此问题。这样,只有队空的时候才有front=rear。使用这种方法利用环形队列实现了”烫手山芋“游戏。烫手山芋游戏规则:一群小孩围成一圈,在他们之间传递山芋。其中,一个小孩负责数数,每数一次,就把山芋转交给左边的邻居,从1开始数起,数到k时拿着山芋的孩子出列,然后重新从1开始说,从”淘汰“孩子的邻居开始重新传递山芋。实现代码如下:

  首先给出Queue接口的代码:

import java.util.Objects;
import java.util.Random;

/**
* Created by hfz on 2016/8/2.
*/
/*
可以仿照利用数组实现栈的过程,使用数组实现队列。以front指向队首元素,值始终为数组首元素a[0]。
出队时,front保持不变,删除队首元素,其余元素依次向前移动,时间复杂度是O(n)。
入队时,根据队列大小将元素存储到相应位置。

上述实现因为不断移动元素,效率太低。因此以下使用环形数组的形式来构造队列。
定义两个变量:
front:指向队首元素。
rear:指向队尾元素的下一个位置。
另外设环形数组大小为len
初始状态下,front=rear=0。入队时,在rear指向的位置存储元素,然后令rear=(rear+1)%len。
出队时,删除front指向的元素,然后令front=(front+1)%len。
最后,front=rear既是队满的判断条件又是队空的判断条件,不过可以完美解决。在入队方法enqueue中,
size==CAPACITY,那么就是队满了。在出队方法中,如果size==0,那么即使队空了。不过这种方法会导致原有队首元素被覆盖(覆盖原队首元素
不符合队列的设计初衷),可以通过禁止队列规模超过CAPACITY-1的方法来解决此问题。这样,只有队空的时候才有front=rear。
各种方法时间复杂度均是O(1)
*/

public class Queue_Array implements Queue {
private static int CAPACITY=40;
private int capacity=0;
private Object[] S;
private int front=0;
private int rear=0;

public Queue_Array(int capacity){
this.capacity=capacity;
S=new Object[capacity];
}
public Queue_Array(){
this(CAPACITY);
}
public void enqueue(Object obj){
if(getSize()==CAPACITY-1){//队满
throw new ExceptionQueueFull("队满,不能入队");
}
else{//队未满,入队
try {

S[rear] = obj;
//front=(front+1)%CAPACITY;//队首指针加1,再对数组长度取模。
rear = (rear + 1) % CAPACITY;//队尾指针加1,再对数组长度取模。
}
catch (ArrayIndexOutOfBoundsException ex){
System.out.println();
}
}

}
public Object dequeue(){
if(rear==front){
throw new ExceptionQueueEmpty("队空,不能出队");
}
else{
Object obj=S[front];
S[front]=null;
front=(front+1)%CAPACITY;
return obj;
}
}

public Object front(){
if(rear==front){
throw new ExceptionQueueEmpty("队空,没有队首元素");
}
else{
return S[front];
}
}
public boolean isEmpty(){
if(front==rear){
return true;
}
else {
return false;
}
}
public int getSize(){
return (CAPACITY+rear-front)%CAPACITY;//rear取模之后可能小于front,不能直接用(rear-front)
}

public static void main(String[] args){
String[] children={"A","B","C","D","E","F","G","H","I","J","K"};
Queue_Array queue=new Queue_Array();
//        int len=queue.capacity;
for(String s:children){
queue.enqueue(s);
}
Random rand=new Random();
Object dequeueObj;
int k=rand.nextInt(children.length-1)+1;
//k=4;
while(queue.getSize()!=1){
for(int i=1;i<k;++i){
dequeueObj=queue.dequeue();
queue.enqueue(dequeueObj);
}
dequeueObj=queue.dequeue();
System.out.println(String.format("%s 退出",(String)dequeueObj));
}
System.out.println(String.format("when k is %s winner is %s ",k,queue.front()));
}
}

class ExceptionQueueEmpty extends RuntimeException {
public ExceptionQueueEmpty(String err){
super(err);
}
}
class ExceptionQueueFull extends RuntimeException{
public ExceptionQueueFull(String err){
super(err);
}
}


View Code
  其实,就烫手山芋游戏来说,使用如下的入队和出队方法更好:

  在入队方法enqueue中,size==CAPACITY,那么就是队满了。在出队方法中,如果size==0,那么即是队空了。这种方法会导致原有队首元素被覆盖,正好符合题意,可以将队列大小设置为孩子个数。如果使用禁止队列规模超过CAPACITY-1的方法,队列大小的设置要大于孩子个数,否则入队时会提示“队列已满”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: