用Array实现队列结构碰到的一些问题

Posted hyper-xl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用Array实现队列结构碰到的一些问题相关的知识,希望对你有一定的参考价值。

Algorithms课程里留了一个作业:用数组实现可自动扩充的队列数据结构。已经给了具体思路,但是实现还遇到了一些问题。
按照Stack的思路照搬,申请一个固定大小(capacity)的数组,用head和tail来指向头和尾。head++表示出队,tail++表示入队。为了方便,我把tail指向尾部的下一个,当head==tail是就为空。实现Stack时为了高效扩充,当超出capacity时将它扩充一倍(申请新数组复制原来的元素),出队时如果数据只占capacity的1/4则缩小一半。这样避免了最坏情况下频繁的扩大和缩小带来的空间和时间消耗。
head如果后移,那么它前面的空间可以再次利用。因此,当tail超出数组时可以移到开头。按照这样的想法,很容想到当tail大于capacity时将其移动到开头,然后根据tail和head的位置来索引队列。按照tail和head的先后一定能够做到啊。但事实是不行,如果仅仅把tail和head的值限制在capacity内时就不行了,比如,如果tail和head碰到了一起那是满了呢还是为空呢?而且,每个操作还有很复杂的判断,当最后知道不可以了后就想放弃这个问题了。但马上灵光乍现,不必要限制tail和head的大小啊,可以通过取其余数来索引啊。于是,问题变得和Stack的实现一样简单。仅仅多了索引的时候记得取余数来索引就好了。
写完碰到了一个小问题没注意,于是一直出错。写resize函数时偷懒,用foreach方式来遍历自己。结果遍历之前先修改了head和tail的值(resize将内容复制到新数组,因此要调整head和tail值),使得依赖这两个值的遍历没法正常完成。好在最后通过多次打印调试发现了这个问题。
附上未经修改为generics的源码,为了调试有的地方还改得麻烦了一点。
···
import java.util.Iterator;
import java.util.NoSuchElementException;

public class ArrayQueue implements Iterable

private int[] list;
private int head,tail;
private int capacity;

@Override
public Iterator<Integer> iterator() {
    return new ListIterator();
}

private class ListIterator implements Iterator<Integer>{

    private int current = head-1;

    @Override
    public boolean hasNext() {
        return current != tail - 1;
    }

    @Override
    public Integer next() {
        current++;
        if(current < tail) {
            return list[idx(current)];
        }
        throw new NoSuchElementException();
    }
}

private void init() {
    list = new int[capacity];
    head = tail = 0;
}

public ArrayQueue(int capacity) {
    this.capacity = capacity;
    init();
}

public ArrayQueue() {
    this.capacity = 10;
    init();
}

public int size() {
    return tail - head;
}

public boolean isEmputy() {
    return size() == 0;
}

public void enqueue(int data) {
    if(size()+1 > capacity) {
        resize(capacity*2);
    }
    list[idx(tail++)] = data;
}

public int dequeue() throws Exception {
    if(isEmputy())
        throw new Exception("Emputy Queue");
    if(size()-1 < capacity/4) {
        resize(capacity/2);
    }
    int item = list[idx(head++)];
    return item;
}

public String toString() {
    String ret = "";
    for( int v : this) {
        ret += v + ", ";
    }
    ret += "capacity="+capacity;
    return ret;
}

private void resize(int capacity) {
    int[] old_list = this.list;
    int[] list = new int[capacity];
    int sz = size();
    Iterator<Integer> iter = this.iterator();
    for(int i=0; iter.hasNext(); i++) {
        list[i] = iter.next();
    }
    head = 0;
    tail = head+sz;
    this.list = list;
    this.capacity = capacity;
}

private int idx(int index) {
    return index % capacity;
}

public static void main(String[] args) throws Exception {
    ArrayQueue que = new ArrayQueue();
    for(int i =1; i<=10; i++) {
        que.enqueue(i);
    }
    System.out.println(que.toString());
    que.enqueue(11);
    que.enqueue(12);
    System.out.println(que.toString());
    que.dequeue();
    que.dequeue();
    que.dequeue();
    que.dequeue();
    que.dequeue();
    que.dequeue();
    que.dequeue();
    System.out.println(que.toString());
    que.dequeue();
    System.out.println(que.toString());
    que.dequeue();
    System.out.println(que.toString());
    que.dequeue();
    System.out.println(que.toString());
    que.dequeue();
    System.out.println(que.toString());
}

}

···

以上是关于用Array实现队列结构碰到的一些问题的主要内容,如果未能解决你的问题,请参考以下文章

6. 队列

JavaScript实现常见的数据结构

数据结构栈和队列OJ练习(栈和队列相互实现+循环队列实现)

用js实现个优先队列吧

数据结构- 栈和队列的实现

数据结构:队列 和 栈 的详解