6.队列

6.1 队列的特点及抽象数据结构

队列(queue)简称队,也是一种受限的线性表。只允许在线性表的一端进行插入,在表的另一端进行删除。插入数据的一端称为队尾(rear),删除数据的一端称为队首(front)。

向队列添加数据称为入队或进队,新入队的元素称为队尾元素。从队列中删除元素称为出队或离队,元素出队之后,它的后继元素称为新的队首元素。

队列是一种先进先出(First In First Out,简称FIFO)表。

队列的抽象数据类型的定义:

ADT Queue{
	数据对象:D={a0,a1,a2,...,ai}  #都是同一数据类型的元素
	数据关系:R={<ai,ai+1>}
	数据操作:
		getSise();  #返回元素个数
		isEmpty();  #判断队列是否为空
		enQueue(e); #入队
		deQueue();  #出队
		peek();     #返回队首的元素
}ADT Queue
6.2 队列的顺序存储实现

在队列的实现中,可以把数组设想称一个圆环,这种数组称为循环数组,用循环数组实现的队列称为循环队列。

用front指针指向队首元素所在的单元,使用rear指针指向队尾所在单元的后一个单元。

在元素入队时,将新入队的单元保存到rear所在的单元,然后rear指针后移。在出队时,将队首指针front指向的元素返回,然后front指针后移。
在这里插入图片描述

队列为空:
在这里插入图片描述

出队:队首指针后移
在这里插入图片描述

入队:队首指针后移
在这里插入图片描述

队列满:队首队尾也是指向同一个单元
在这里插入图片描述

  • 如何表示队列为空还是满?

    • 一般情况下,采用两种方式表示队列已满

      1. 少用一个存储单元,当队尾指针的下一个单元是队首指针的时,停止入队,(rear+1) % 容量 == front时表示队列满,当front == rear时,队列为空。
        在这里插入图片描述

      2. 增设一个标志表示队列为空还是已满,通常用size变量表示元素的个数,当size == 0时,队列为空,当size == 容量 时,表示队列已满。

代码实现

/**
 * 队列的顺序存储
 */
public class MyArrayQueue {
    private Object[] elements;   //定义数组存储队列中的元素
    private static final int DEFAULT_LENGTH =  8;
    private int front;   //队首
    private int rear;    //队尾
    private int size;    //元素个数
    //构造方法,指定数组大小
    public MyArrayQueue(){
        elements = new Object[DEFAULT_LENGTH];
    }
    public MyArrayQueue(int initialLength){
        elements = new Object[initialLength];
    }

    //返回元素个数
    public int getSize(){
        return size;
    }

    //判断队列是否为空
    public boolean isEmpty(){
        return size == 0;
    }

    //入队
    public void enQueue(Object e){

        //如果队列已满,对数组扩容
        if(size >= elements.length){
            expandQueue();
        }

        elements[rear] = e;  //把元素存储到rear指针指向的单元
        rear = (rear + 1) % elements.length;  //rear指针后移
        size++;  //元素个数+1
    }

    //队列的数组扩容
    private void expandQueue() {
        //定义一个更大的数组
        Object[] newElements = new Object[elements.length * 2];  //两倍扩容
        //把原来的数组复制到新的数组中,从队首开始的元素依次开始复制新数组
        for(int i = 0;i<elements.length;i++){
            newElements[i] = elements[front];  //新数组0位置的元素应该等于element队首位置的元素
            front = (front + 1) % elements.length;
        }
        //把原来的数组名指向新的数组
        elements = newElements;
        //调整新的队首和队尾指针
        front = 0;
        rear = size;
    }

    //出队
    public Object deQueue(){
        //队列为空
        if(size <= 0){
            //抛出一个队列为空的异常
            throw new QueueEmptyException("队列为空");  //自定义异常
        }
        //队列不为空,返回front指向的元素返回,front指针后移
        Object old = elements[front];
        front = (front + 1) % elements.length;
        size--;
        return old;
    }

    //返回队首元素
    public Object peek(){
        //队列为空
        if(size <= 0){
            //抛出一个队列为空的异常
            throw new QueueEmptyException("队列为空");
        }
        return elements[front];
    }
}

自定义异常

/**
 * 自定义队列为空的异常
 * 该异常是一个运行时异常,不需要开发人员预处理
 * RuntimeException 的子类就是运行时异常
 */
public class QueueEmptyException extends RuntimeException{
    public QueueEmptyException() {
    }

    //String参数,传递的就是异常信息
    public QueueEmptyException(String message) {
        super(message);
    }
}

代码测试

public class QueueTest {
    public static void main(String[] args) {
        MyArrayQueue queue = new MyArrayQueue();

        //入队
        queue.enQueue("a");
        queue.enQueue("b");
        queue.enQueue("c");
        queue.enQueue("d");

        //返回队首元素
        System.out.println(queue.peek());  //a
        //出队
        System.out.println(queue.deQueue()); // a
        System.out.println(queue.deQueue()); // b
        System.out.println(queue.deQueue()); // c
        System.out.println(queue.deQueue()); // d
        //System.out.println(queue.deQueue()); //自定义异常:Exception in thread "main" cn.xue.queue.QueueEmptyException: 队列为空
        queue.enQueue("1");
        queue.enQueue("2");
        queue.enQueue("3");
        queue.enQueue("4");
        queue.enQueue("5");
        queue.enQueue("6");
        queue.enQueue("7");
        queue.enQueue("8");
        queue.enQueue("9");
        queue.enQueue("10");
        queue.enQueue("J");
        queue.enQueue("Q");
        queue.enQueue("K");
        queue.enQueue("joker");

        //返回队首元素
        System.out.println(queue.peek());  //1
    }
}
6.3 队列的链式存储实现

使用单向链表实现队列
把链表的头部作为队首,链表的尾部作为队尾。
在这里插入图片描述
代码实现

/**
 * 队列的链式存储
 */
public class MyLinkQueue {

    private Node front;  //队首
    private Node rear;   //队尾
    private int size;    //元素的个数

    //返回元素的个数
    public int getSize(){
        return size;
    }

    //判断队列是否为空
    public boolean isEmpty(){
        return size == 0;
    }

    //入队
    public void enQueue(Object e){
        //根据添加的元素生成一个结点
        Node newNode = new Node(e,null);
        //把结点连接到队列中
        if(rear == null){  //队列为空,新结点既是头结点,又是尾结点
            rear = newNode;
            front = newNode;
        }else{
            //把结点连接到队列的尾部
            rear.next = newNode;
            rear = newNode;  //rear指针指向新添加的元素
        }
    }

    //出队
    public Object deQueue(){
        //队列为空
        if(size <= 0){
            //抛出一个队列为空的异常
            throw new QueueEmptyException("队列为空");  //自定义异常
        }
        Object old = front.element;  //保存头结点的元素
        front = front.next;  //调整队首指针,队首指针下移
        //如果出队后,队列为空,调整队尾指针
        if(front == null){
            rear = null;
        }
        size--;
        return old;
    }

    //返回队首元素
    public Object peek(){
        //队列为空
        if(size <= 0){
            //抛出一个队列为空的异常
            throw new QueueEmptyException("队列为空");  //自定义异常
        }
        return front.element;
    }

    //通过内部类表示单项链表的结点
    private class Node{
        Object element;
        Node next;
        public Node(Object element,Node next){
            this.element = element;
            this.next = next;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值