队列--数组实现
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接口的代码:
View Code
其实,就烫手山芋游戏来说,使用如下的入队和出队方法更好:
在入队方法enqueue中,size==CAPACITY,那么就是队满了。在出队方法中,如果size==0,那么即是队空了。这种方法会导致原有队首元素被覆盖,正好符合题意,可以将队列大小设置为孩子个数。如果使用禁止队列规模超过CAPACITY-1的方法,队列大小的设置要大于孩子个数,否则入队时会提示“队列已满”。
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的方法,队列大小的设置要大于孩子个数,否则入队时会提示“队列已满”。
相关文章推荐
- 数据结构循环队列——数组模拟实现
- 优先队列的数组实现
- FIFO队列实现-------循环数组实现
- 深入理解循环队列----循环数组实现ArrayDeque
- [模板] 二叉堆 - 优先队列的二叉堆数组实现
- 顺序队列(数组实现)
- 队列的链表与数组实现
- 斐波那契数列实现--递归,迭代,数组,队列
- 8.用定长数组 实现 循环队列
- 数组实现循环队列
- 使用数组和模板实现的队列
- 基于数组的循环队列(C++模板实现)
- 用数组实现队列(C实现)
- 用数组结构实现大小固定的栈和队列
- 队列—链表与循环数组实现
- 数据结构--队列之C数组实现
- js利用数组实现队列与堆栈效果
- 用Java数组实现队列
- 中缀表达式转后缀表达式(用于求字符串表达式值)(js栈和队列的实现是通过数组的push和unshift方法插值,pop方法取值)
- 动态数组实现队列