队列--数组实现

  可以仿照利用数组实现栈的过程,使用数组实现队列。以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接口的代码:

 1 /**
 2  * Created by hfz on 2016/8/2.
 3  */
 4 public interface Queue {
 5     void enqueue(Object obj);//入队
 6     Object dequeue();//出队并返回对首元素
 7     int getSize();//队列元素个数
 8     boolean isEmpty();//判断队列是否为空
 9     Object front();//返回对首元素
10 }
View Code

  然后是实现代码:

  1 import java.util.Objects;
  2 import java.util.Random;
  3 
  4 /**
  5  * Created by hfz on 2016/8/2.
  6  */
  7 /*
  8 可以仿照利用数组实现栈的过程,使用数组实现队列。以front指向队首元素,值始终为数组首元素a[0]。
  9 出队时,front保持不变,删除队首元素,其余元素依次向前移动,时间复杂度是O(n)。
 10 入队时,根据队列大小将元素存储到相应位置。
 11 
 12 上述实现因为不断移动元素,效率太低。因此以下使用环形数组的形式来构造队列。
 13 定义两个变量:
 14 front:指向队首元素。
 15 rear:指向队尾元素的下一个位置。
 16 另外设环形数组大小为len
 17 初始状态下,front=rear=0。入队时,在rear指向的位置存储元素,然后令rear=(rear+1)%len。
 18 出队时,删除front指向的元素,然后令front=(front+1)%len。
 19 最后,front=rear既是队满的判断条件又是队空的判断条件,不过可以完美解决。在入队方法enqueue中,
 20 size==CAPACITY,那么就是队满了。在出队方法中,如果size==0,那么即使队空了。不过这种方法会导致原有队首元素被覆盖(覆盖原队首元素
 21 不符合队列的设计初衷),可以通过禁止队列规模超过CAPACITY-1的方法来解决此问题。这样,只有队空的时候才有front=rear。
 22 各种方法时间复杂度均是O(1)
 23  */
 24 
 25 public class Queue_Array implements Queue {
 26     private static int CAPACITY=40;
 27     private int capacity=0;
 28     private Object[] S;
 29     private int front=0;
 30     private int rear=0;
 31 
 32     public Queue_Array(int capacity){
 33         this.capacity=capacity;
 34         S=new Object[capacity];
 35     }
 36     public Queue_Array(){
 37         this(CAPACITY);
 38     }
 39     public void enqueue(Object obj){
 40         if(getSize()==CAPACITY-1){//队满
 41             throw new ExceptionQueueFull("队满,不能入队");
 42         }
 43         else{//队未满,入队
 44             try {
 45 
 46                 S[rear] = obj;
 47                 //front=(front+1)%CAPACITY;//队首指针加1,再对数组长度取模。
 48                 rear = (rear + 1) % CAPACITY;//队尾指针加1,再对数组长度取模。
 49             }
 50             catch (ArrayIndexOutOfBoundsException ex){
 51                 System.out.println();
 52             }
 53         }
 54 
 55     }
 56     public Object dequeue(){
 57         if(rear==front){
 58             throw new ExceptionQueueEmpty("队空,不能出队");
 59         }
 60         else{
 61             Object obj=S[front];
 62             S[front]=null;
 63             front=(front+1)%CAPACITY;
 64             return obj;
 65         }
 66     }
 67 
 68     public Object front(){
 69         if(rear==front){
 70             throw new ExceptionQueueEmpty("队空,没有队首元素");
 71         }
 72         else{
 73              return S[front];
 74         }
 75     }
 76     public boolean isEmpty(){
 77         if(front==rear){
 78             return true;
 79         }
 80         else {
 81             return false;
 82         }
 83     }
 84     public int getSize(){
 85         return (CAPACITY+rear-front)%CAPACITY;//rear取模之后可能小于front,不能直接用(rear-front)
 86     }
 87 
 88 
 89     public static void main(String[] args){
 90         String[] children={"A","B","C","D","E","F","G","H","I","J","K"};
 91         Queue_Array queue=new Queue_Array();
 92 //        int len=queue.capacity;
 93        for(String s:children){
 94            queue.enqueue(s);
 95        }
 96         Random rand=new Random();
 97         Object dequeueObj;
 98         int k=rand.nextInt(children.length-1)+1;
 99         //k=4;
100         while(queue.getSize()!=1){
101             for(int i=1;i<k;++i){
102                 dequeueObj=queue.dequeue();
103                 queue.enqueue(dequeueObj);
104             }
105             dequeueObj=queue.dequeue();
106             System.out.println(String.format("%s 退出",(String)dequeueObj));
107         }
108         System.out.println(String.format("when k is %s winner is %s ",k,queue.front()));
109     }
110 }
111 
112 class ExceptionQueueEmpty extends RuntimeException {
113     public ExceptionQueueEmpty(String err){
114         super(err);
115     }
116 }
117 class ExceptionQueueFull extends RuntimeException{
118     public ExceptionQueueFull(String err){
119         super(err);
120     }
121 }
View Code

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

  在入队方法enqueue中,size==CAPACITY,那么就是队满了。在出队方法中,如果size==0,那么即是队空了。这种方法会导致原有队首元素被覆盖,正好符合题意,可以将队列大小设置为孩子个数。如果使用禁止队列规模超过CAPACITY-1的方法,队列大小的设置要大于孩子个数,否则入队时会提示“队列已满”。

 

posted @ 2016-08-02 11:23  lz3018  阅读(4429)  评论(0编辑  收藏  举报