队列的简单学习

来源:互联网 发布:护理优化服务流程 编辑:程序博客网 时间:2024/06/05 08:27

队列

队列也是一种有序数据项构成的数据结构,和栈不相同的是,操作队列的数据项是一边进一边出,只能在队尾(rear)插入数据项在队头(front)移出数据项并且栈的数据项是后进先出(last in first out),而队列是先进先出(first in fisrt out)。

可以用数组简单实现一个队列,定义两个下标front和rear代表队列的首尾,数据项存储在数组中的data[front]…data[rear]。

队列的存储方式也有两种可以选择:
1.让下标front恒为数组data的起始位置data[0],每次有元素出列,让后面的元素不断往前移。
2.让队列形成一个类似环的结构,当不断有元素出列,front下标前的空间被空出来;又不断有元素进列,当rear走到数组的末端的时候,就可以利用front前端的空间,重新再利用空间。也就是说队列的第一个元素紧跟着最后一个元素的后面,而队列最后一个元素的下一个元素就是队列的第一个元素。这种方式相对第一种效率就比较高一些。

A B 0 1 2 3 4

假设现在有个data数组实现的队列,已经有A、B两个元素进入队列,front指向下标0,rear指向下标1。
当再加入C、D、E三个元素又将A出列,队列如下图所示

B C D E 0 1 2 3 4

这时候front指向下标1,rear指向下标4。
当再添加一个元素F,此时rear已经到达了数据的末端,而front前端的空间是可以利用的,所以元素F就插到前面去了。

F B C D E 0 1 2 3 4

此时front指向下标1,而rear则指向下标0。
下面是队列的简单实现

public class ArrayQueue<E> implements Cloneable{    private E[] data;       //存放队列的元素    private int items;      //队列元素的个数    private int front;      //队列的队头位置    private int rear;       //队列的队尾位置    //当实例化一个队列的时候,给队列一个长度为INITIAL_LENGTH    public ArrayQueue(){        final int INITIAL_LENGTH = 10;        items = 0;        data = (E[]) new Object[INITIAL_LENGTH];    }    //手动给队列一个初始长度    public ArrayQueue(int initialLength){        if(initialLength < 0)            throw new IllegalArgumentException("队列初始长度不能为负数!");        items = 0;        data = (E[]) new Object[initialLength];    }    //判断队列是否为空    public boolean isEmpty(){        return (items == 0);    }    //获取队列的长度    public int getLength(){        return data.length;    }    //获取队列元素个数    public int itemsSize(){        return items;       }    //修改队列的长度    public void changeLength(int newLength){        E[] newQueue;        int index1, index2;        if(data.length >= newLength)            return;        else if(items == 0)            data = (E[]) new Object[newLength];        //如果现有队列是个小队列,那么新建一个队列把数据项都复制过去        else if(front < rear){            newQueue = (E[]) new Object[newLength];            System.arraycopy(data, front, newQueue, front, items);            data = newQueue;        }        //现有队列形成了一个类似环的结构,分段处理两端的数据到新的队列        else{            newQueue = (E[]) new Object[newLength];            index1 = data.length - front;            index2 = rear + 1;            System.arraycopy(data, front, newQueue, 0, index1);            System.arraycopy(data, 0, newQueue, index1, index2);            front = 0;            rear = items - 1;            data = newQueue;        }    }    //实现Cloneable的clone方法    public ArrayQueue<E> clone(){        ArrayQueue<E> queueCopy;        try{            queueCopy = (ArrayQueue<E>) super.clone();        }        catch(CloneNotSupportedException e){            throw new RuntimeException("复制失败!这个数据类型没有实现clone方法!")        }        queueCopy.data = data.clone();        return queueCopy;    }}

下面就是数据项在队列中是如何入列跟出列的方法实现:

    //将新元素添加到队列中    public void add(E newItem){        if(items == data.length)            changeLength(2*items - 1);        if(items == 0){            front = 0;            rear = 0;        }        else{            //定义一个队尾下标后移的辅助方法            rear = nextIndex(rear);        }        data[rear] = newItem;        items++;    }    //队尾下标后移的辅助方法    private int nextIndex(int i){        if(++i == data.length)            return 0;        else            return i;    }    //将元素出列    public E remove(){        E head;        if(items == 0)            throw new NoSuchElementException("队列为空!");        head = data[front];        front = nextIndex(front);        items--;        return head;    }    //和栈一样,因为将元素添加到队列的时候改变了队列的大小,所以要把它恢复到实际大小    public void trimToSize(){        ArrayQueue<E> newQueue;        if(items == data.length)            return;        else if(items == 0)            data.length = 0;        else if(front < rear){            newQueue = (E[]) new Object[items];            System.arraycopy(data, front, newQueue, items);            data = newQueue;        }        else{            newQueue = (E[]) new Object[items];            int index1 = data.length - front;            int index2 = rear + 1;            System.arraycopy(data, front, newQueue, index1);            System.arraycopy(data, 0, newQueue, index1, index2);            front = 0;            rear = items - 1;            data = newQueue;        }    }

和栈一样,队列也能用链表实现,实现的方式跟数组的实现方式是相近的。

public class LinkedQueue<E> implements Cloneable{    private int nodes;    private Node<E> front;    private Node<E> rear;    //初始化队列的头尾引用为空    public LinkedQueue(){        front = null;        rear = null;    }    //判断队列是否为空    public boolean isEmpty(){        return (nodes == 0);    }    //获取队列元素个数    public int nodeSize(){        return nodes;    }    //获取当前队列的一个副本,返回副本的头尾引用    public LinkedQueue<E> clone(){        Node[] copyInfo;        LinkedQueue<E> queueCopy = new LinkedQueue<E>();        copyInfo = Node.listCopyWithArray(front);        queueCopy.front = copyInfo[0];        queueCopy.rear = copyInfo[1];        return copyInfo;    }}    //将元素入列    public void add(E newNode){        if(isEmpty()){            front = new Node<E>(newNode, null);            rear = front;        }        else{            rear.addNodeAfter(newNode);            rear = rear.getLink();        }        nodes++;    }    //将元素出列    public E remove(){        E head;        if(nodes == 0)            throw new NoSuchElementException("队列不能为空!");        head = front.getData();        front = front.getLink();        nodes--;        if(nodes == 0)            rear = null;        return head;    }
0 0
原创粉丝点击