【数据结构 四】---队列

来源:互联网 发布:校园网络直播系统 编辑:程序博客网 时间:2024/06/14 09:38

下午的时候全面总结了栈的两种实现方式和基本原理,然后晚上来做以下关于队列的基本总结,今天的工作就算结束了。代码实现是我用java完成的,实现过程中参照了以下两篇博客http://blog.csdn.net/wuwenxiang91322/article/details/12259099和
http://www.cnblogs.com/CherishFX/p/4608880.html在这里注明出处,时间是2017.8.2晚上。

队列简介

队列的特点

这里写图片描述
队列(Queue)是只允许在一端进行插入,而在另一端进行删除的运算受限的线性表。
(1)允许删除的一端称为队头(Front)。
(2)允许插入的一端称为队尾(Rear)。
(3)当队列中没有元素时称为空队列。
(4)队列亦称作先进先出(First In First Out)的线性表,简称为FIFO表。
队列的修改是依先进先出的原则进行的。新来的成员总是加入队尾,每次离开的成员总是队列头上的(不允许中途离队)。

队列的相关概念

1,队头下标(Front)
2,队尾下标(Rear)

队列的基本运算

1,判断队列是否为空(isEmpty):队空的条件是front=rear
2, 返回队首元素,但不删除(peek)
3,入队(add)
4,出队(del)
5,队列长度(length)

队列的实现方式

队列接口实现队列

package queue;import java.util.LinkedList;/*add      增加一个元索                     如果队列已满,则抛出一个IIIegaISlabEepeplian异常 *remove   移除并返回队列头部的元素    如果队列为空,则抛出一个NoSuchElementException异常 *element  返回队列头部的元素             如果队列为空,则抛出一个NoSuchElementException异常 *offer    添加一个元素并返回true       如果队列已满,则返回false *poll     移除并返问队列头部的元素    如果队列为空,则返回null *peek     返回队列头部的元素             如果队列为空,则返回null *put      添加一个元素                      如果队列满,则阻塞 *take     移除并返回队列头部的元素     如果队列为空,则阻塞 */public class Queue {    public static void main(String[] args) {        java.util.Queue<Integer> queue = new LinkedList<Integer>();        queue.offer(1);        queue.offer(2);        queue.offer(3);        queue.offer(4);        System.out.println("队列大小" + queue.size());        System.out.println("队头元素" + queue.peek());        System.out.println("移除并返回队头元素" + queue.poll());        System.out.println("队头元素" + queue.peek());        System.out.println("打印队列" + queue);    }}

测试结果

队列大小4队头元素1移除并返回队头元素1队头元素2打印队列[2, 3, 4]

队列的顺序数组实现(数组)

队列的数组实现

package queue;public class MyQueueArray<T> {    public int initalSize; // 队列的初始化容量    public int curSize; // 队列的当前大小    public T[] array; // 用于存放数据的数组    public int front; // 队头下标    public int rear; // 队尾下标    public MyQueueArray() {        this(5);    }    @SuppressWarnings("unchecked")    public MyQueueArray(int Size) {        if (Size >= 0) {            initalSize = Size;            array = (T[]) new Object[Size];            front = 0;            rear = 0;            curSize = 0;        }    } // 两个构造函数,用于初始化队列        // 判断队列是否为空    public boolean isEmpty() {        return rear == front;    }    // 入队列:rear向后移动    public void add(T data) {        if (curSize == initalSize) {            throw new RuntimeException("队列已满,无法插入新的元素!");        }        array[rear] = data;        rear++;        curSize++;    }    // 返回队头元素    public T peek() {        if (isEmpty()) {            System.out.println("队列为空");        }        return array[front];    }    // 出队列:front向后移动    public T del() {        if (isEmpty()) {            System.out.println("队列为空");        }        T deldata = array[front];        array[front++] = null; //        curSize--;        return deldata;    }    // 队列长度    public int length() {        return rear - front; // 理论上应该与curSize大小相同,为什么不是rear-front+1,因为每次存入一个元素后,rear移动到了下一个没有元素的位置了。    }}

测试代码

package queue;public class QueneArrayTest {    public static void main(String[] args) {          MyQueueArray<Integer> t = new MyQueueArray<Integer>();          t.add(5);          t.add(4);          t.add(3);          t.add(2);          t.add(1);          System.out.println("队列的长度是"+ t.curSize);          System.out.println("队列的长度是"+ t.length());          System.out.println("队头元素是"+ t.peek());          t.del();          System.out.println("队列的长度是"+ t.length());          System.out.println("队头元素是"+ t.peek());          t.add(0);          System.out.println("队列的长度是"+ t.length());          t.add(1);          System.out.println("队列的长度是"+ t.length());    }}

测试结果

队列的长度是5队列的长度是5队头元素是5队列的长度是4队头元素是4报错,数组溢出  // 虽然之前的队头元素被删除了,但是队列的总空间还是被占用了,再往后加进来就会报错。

循环队列的数组实现(数组)

循环队列的实现方式其实也就是顺序实现方式的防溢出形式。

由于队列的队头和队尾的位置是变化的,设置两个指针front和rear分别指示队头元素和队尾元素,它们的初值在队列初始化时均应置为0。
这里写图片描述

入队时:将新元素插入rear所指的位置的后一位。
出队时:删去front所指的元素,然后将front加1并返回被删元素。

①“下溢”现象
当队列为空时,做出队运算产生的溢出现象。“下溢”是正常现象,常用作程序控制转移的条件。

② “真上溢”现象
当队列满时,做进栈运算产生空间溢出的现象。“真上溢”是一种出错状态,应设法避免。

③ “假上溢”现象
由于入队和出队操作中,头尾指针只增加不减小,致使被删元素的空间永远无法重新利用。当队列中实际的元素个数远远小于内存中本分配的空间时,也可能由于尾指针已超越向量空间的上界而不能做入队操作。该现象称为”假上溢”现象。如下图

这里写图片描述

循环链表实现队列

package queue;public class LoopQueue<T> {    public int initalSize; // 队列的初始化容量    public int curSize; // 队列的当前大小    public T[] array; // 用于存放数据的数组    public int front; // 队头下标    public int rear; // 队尾下标    public LoopQueue() {        this(5);    }    @SuppressWarnings("unchecked")    public LoopQueue(int Size) {        if (Size >= 0) {            initalSize = Size;            array = (T[]) new Object[Size];            front = 0;            rear = 0;            curSize = 0;        }    } // 两个构造函数,用于初始化队列    // 判断队列是否为空    public boolean isEmpty() {        return curSize==0;    }    // 判断队列是否为满    public boolean isFull() {        if ((rear + 1) % initalSize == front)  //该条件可以判断队列是否已满            return true;        return false;    }    // 入队列:rear向后移动    public void add(T data) {        if (curSize == initalSize) {   //这里之所以可以用curSize判断是否为满,就是因为该队列是循环队列            throw new RuntimeException("队列已满,无法插入新的元素!");        }        array[rear] = data;        rear = (rear + 1) % initalSize;  //循环到下一个位置        curSize++;    }    // 返回队头元素    public T peek() {        if (isEmpty()) {            System.out.println("队列为空");        }        return array[front];    }    // 出队列:front向后移动    public T del() {        if (isEmpty()) {            System.out.println("队列为空");        }        T deldata = array[front];        front = (front+1)%initalSize;        curSize--;        return deldata;    }}

测试代码

package queue;public class QueneLoopTest {    public static void main(String[] args) {          LoopQueue<Integer> t = new LoopQueue<Integer>();          t.add(5);          t.add(4);          t.add(3);          t.add(2);          t.add(1);          System.out.println("队列的长度是"+ t.curSize);          System.out.println("队头元素是"+ t.peek());          t.del();          System.out.println("队头元素是"+ t.peek());          t.add(0);          System.out.println("队列的长度是"+ t.curSize);          t.del();          t.add(9);          System.out.println("队列的长度是"+ t.curSize);    }}

测试结果

队列的长度是5队列的长度是5队头元素是5队列的长度是4队头元素是4    //这里可以看到,队列可以反复的增加和删除而没有影响。

链式队列的实现(单链表)

这里写图片描述

节点代码实现:

package queue;public class Node<T> {    public T val;    public Node<T> next = null;    public Node(T val, Node<T> next) {   //构造方法,创建一个新节点        this.val = val;        this.next = next;    }}

队列的链式结构实现

package queue;public class MyQueneList<T> {    public int curSize; // 队列的当前大小    public Node<T> front; // 队头下标    public Node<T> rear; // 队尾下标    // 判断队列是否为空    public boolean isEmpty() {        return curSize == 0; // 注意这里一定不能用rear==font,因为链表而言,rear指向的节点是有元素的,    }    // 入队列:rear向后移动    public void add(T data) {        if (isEmpty()) {            Node<T> head = new Node<T>(data, null);            front = head;            rear = head;        } else {            Node<T> newNode = new Node<T>(data, null);            rear.next = newNode;            rear = newNode;        }        curSize++;    }    // 返回队头元素    public T peek() {        if (isEmpty()) {            System.out.println("队列为空");        }        return front.val;    }    // 出队列:front向后移动    public T del() {        if (isEmpty()) {            System.out.println("队列为空");        }        Node<T> delNode = front;        front = front.next;        delNode.next = null; // 释放原队列头元素的next引用        curSize--;        return delNode.val;    }}

测试代码

package queue;public class QueneListTest {    public static void main(String[] args) {        MyQueneList<Integer> t = new MyQueneList<Integer>();        t.add(5);        t.add(4);        t.add(3);        t.add(2);        t.add(1);        System.out.println("队列的长度是" + t.curSize);        System.out.println("队头元素是" + t.peek());        t.del();        System.out.println("队头元素是" + t.peek());        t.add(0);        t.add(1);        System.out.println("队列的长度是" + t.curSize);    }}

测试结果

队列的长度是5队头元素是5队头元素是4队列的长度是6

linkedList实现队列

/** * 使用java.util.Queue接口,其底层关联到一个LinkedList(双端队列)实例. */import java.util.LinkedList;import java.util.Queue;public class QueueList<E> {    private Queue<E> queue = new LinkedList<E>();    // 将指定的元素插入此队列(如果立即可行且不会违反容量限制),在成功时返回 true,    //如果当前没有可用的空间,则抛出 IllegalStateException。    public boolean add(E e){        return queue.add(e);    }    //获取,但是不移除此队列的头。    public E element(){        return queue.element();    }    //将指定的元素插入此队列(如果立即可行且不会违反容量限制),当使用有容量限制的队列时,    //此方法通常要优于 add(E),后者可能无法插入元素,而只是抛出一个异常。    public boolean offer(E e){        return queue.offer(e);    }    //获取但不移除此队列的头;如果此队列为空,则返回 null    public E peek(){        return queue.peek();    }    //获取并移除此队列的头,如果此队列为空,则返回 null    public E poll(){        return queue.poll();    }    //获取并移除此队列的头    public E remove(){        return queue.remove();    }    //判空    public boolean empty() {        return queue.isEmpty();    }}
原创粉丝点击