zoukankan      html  css  js  c++  java
  • 队列--数组实现

      可以仿照利用数组实现栈的过程,使用数组实现队列。以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的方法,队列大小的设置要大于孩子个数,否则入队时会提示“队列已满”。

  • 相关阅读:
    深入理解.NET(第2版.英文影印版)书评
    揭示同步块索引(上):从lock开始
    【读书笔记】.NET本质论第一章 The CLR as a Better COM
    【翻译】TestAfter Development is not TestDriven Development
    【读书笔记】.NET本质论第二章Components(Part One)
    Python和Ruby:流行动态脚本语言之特点对比
    C++ Unit Testing Framework: A Boost Test Tutorial——part2:Using Boost Test
    组态软件开发(zz)
    用于实现拖入操作的通用类
    找到一个脚本引擎
  • 原文地址:https://www.cnblogs.com/lz3018/p/5728581.html
Copyright © 2011-2022 走看看