队列的定义和实现

队列的定义和实现

前言

  • 语言:Java
  • 环境:IntelliJ IDEA
  • JDK版本:1.8
  • 源码:GitHub

队列的定义

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

队列的特点:

  • 先进先出(FIFO),插入数据从队尾插入,取出数据从队头取出
  • 无论是数组还是链表实现,通常需要两个变量(指针)来标记队头和队尾

队列的实现

数组实现队列

数组实现队列的几种情况:

数组1-1

数组1-2

数组1-3

数组1-4

由上面四种情况可得到以下信息:

  • 初始值front=rear=-1
  • front指向第一个数据的前面,rear直接指向最后一个数据
  • 判断队列为空的条件是front==rear
  • 判断队列满的条件是rear==maxSize-1
  • 有效数据个数为rear-front
  • 入队时先增加rear,再在rear处插入数据
  • 出队时先增加front,再在front处取出数据
public class ArrayQueue {
    private Integer maxSize = 3;    //队列最大可容纳对象数
    private Integer front = -1;  //始终指向第一个数据之前
    private Integer rear = -1;  //指向最后一个数据
    private Employee[] employeeQueue;   //存放数据的数组
    public ArrayQueue(){
        employeeQueue = new Employee[this.maxSize];
    }
    public ArrayQueue(Integer maxSize){
        this.maxSize = maxSize;
        employeeQueue = new Employee[this.maxSize];
    }

    /**
     *  添加一个数据,添加到尾部,添加成功返回true,失败返回false
     */
    public boolean addEmployee(Employee employee){
        if(this.isFull()){
            return false;
        }
        this.rear++;    //队列添加数据时,将last需要后移
        this.employeeQueue[this.rear] = employee;
        return true;
    }

    /*
     *  获取第一条数据,获取后会从队列中移除
     */
    public Employee getEmployee(){
        if(this.isEmpty()){
            return null;
        }
        this.front++;   //移除数据实际上是将first后移,使其无法访问前面的数组
        return this.employeeQueue[this.front];
    }

    /**
     *  显示第一条数据,仅显示,不会从队列移除
     */
    public Employee showEmployee(){
        if(this.isEmpty()){
            return null;
        }
        return this.employeeQueue[this.front+1];
    }

    /**
     * 队列是否为空
     */
    public boolean isEmpty(){
        return this.front == this.rear;
    }

    /**
     *  队列是否已满
     */
    public boolean isFull(){
        return this.rear == this.maxSize-1;
    }
    /**
     * 将队列的所有数据格式化显示
     */
    public String formatQueue(){
        if(this.isEmpty()){
            return "[]";
        }
        String str = "";
        for(int i = this.front;i<this.rear;i++){
            str += this.employeeQueue[i+1].toString()+"\n";
        }
        return str;
    }
}

优点:

  • 容易理解,便于实现

缺点:

  • 队列容纳的数据数量有限制
  • 为一次性使用的队列,每取出数据,则之前的位置就无法再次使用,如果将该队列插入满数据,再全部取出,那么虽然该队列理论上为空,但实际队列容量已经为0

环形数组实现队列

第一种实现方式: 当front和rear移动至maxSize-1时,将其再移动到数组的开始,以此循环使用

环形数组1-1

环形数组1-2

环形数组1-3

环形数组1-4

由上面四种情况可得到以下信息:

  • 初始值front=rear=0
  • front始终指向第一个数据,rear指向最后一个数据后的空间
  • 判断队列为空的条件是front==rear
  • 判断队列满的条件是(rear+1)%maxSize==front
  • 有效数据个数为(rear+maxSize-front)%maxSize
  • 入队时直接在rear处插入数据,再使rear后移(后移需要取模)
  • 出队时直接取出front处的数据,再使front后移(后移需要取模)
public class CircleArrayQueue1 {
    private Integer maxSize = 3;    //队列最大可容纳对象数
    private Integer front = 0;  //指向第一个数据
    private Integer rear = 0;  //指向最后一个数据的后一个空区域
    private Employee[] employeeQueue;   //存放数据的数组
    public CircleArrayQueue1(){
        employeeQueue = new Employee[this.maxSize];
    }
    public CircleArrayQueue1(Integer maxSize){
        this.maxSize = maxSize;
        employeeQueue = new Employee[this.maxSize];
    }

    /**
     *  添加一个数据,添加到尾部,添加成功返回true,失败返回false
     */
    public boolean addEmployee(Employee employee){
        if(this.isFull()){
            return false;
        }
        this.employeeQueue[this.rear] = employee;
        this.rear = (this.rear+1)%this.maxSize;
        return true;
    }

    /*
     *  获取第一条数据,获取后会从队列中移除
     */
    public Employee getEmployee(){
        if(isEmpty()){
            return null;
        }
        Employee employee = this.employeeQueue[this.front];
        this.front = (this.front+1)%this.maxSize;
        return employee;
    }

    /**
     *  显示第一条数据,仅显示,不会从队列移除
     */
    public Employee showEmployee(){
        if(isEmpty()){
            return null;
        }
        Employee employee = this.employeeQueue[this.front];
        return employee;
    }

    /**
     * 队列是否为空
     */
    public boolean isEmpty(){
        return this.rear == this.front;
    }

    /**
     *  队列是否已满
     */
    public boolean isFull(){
        return (this.rear+1)%this.maxSize == this.front;
    }
    /**
     * 将队列的所有数据格式化显示
     */
    public String formatQueue(){
        if(isEmpty()){
            return "[]";
        }
        String str = "";
        for (int i = this.front;i<this.front+(this.rear + this.maxSize - this.front)%this.maxSize ;i++){
            str += employeeQueue[i%this.maxSize]+"\n";
        }
        return str;
    }
}

优点:

  • 解决了移出数据后空间无法再次使用的问题

缺点:

  • 队列容纳的数据数量有限制
  • 会空出一个位置,即当队列最大容量为6时,实际只能插入5个数据

第二种实现方式: front和rear不再被maxSize限制,只有当使用front和rear时,通过maxSize寻找其在数组中的实际位置

环形数组2-1

环形数组2-2

环形数组2-3

环形数组2-4

由上面四种情况可得到以下信息:

  • 初始值front=rear=-1
  • front始终指向第一个数据的前一个位置,rear指向最后一个数据
  • 判断队列为空的条件是front==rear
  • 判断队列满的条件是rear-front=maxSize
  • 有效数据个数为rear-front
  • 入队时先增加rear,再在rear处插入数据
  • 出队时先增加front,再取出front处的数据
public class CircleArrayQueue2 {
    private Integer maxSize = 3;    //队列最大可容纳对象数
    private Integer front = -1;  //始终指向第一个数据之前
    private Integer rear = -1;  //始终指向最后一个数据
    private Employee[] employeeQueue;   //存放数据的数组
    public CircleArrayQueue2(){
        employeeQueue = new Employee[this.maxSize];
    }
    public CircleArrayQueue2(Integer maxSize){
        this.maxSize = maxSize;
        employeeQueue = new Employee[this.maxSize];
    }

    /**
     *  添加一个数据,添加到尾部,添加成功返回true,失败返回false
     */
    public boolean addEmployee(Employee employee){
        if(this.isFull()){
            return false;
        }
        this.rear++;
        this.employeeQueue[this.rear%this.maxSize] = employee;
        return true;
    }

    /*
     *  获取第一条数据,获取后会从队列中移除
     */
    public Employee getEmployee(){
        if(isEmpty()){
            return null;
        }
        this.front++;
        return this.employeeQueue[this.front%this.maxSize];
    }

    /**
     *  显示第一条数据,仅显示,不会从队列移除
     */
    public Employee showEmployee(){
        if(isEmpty()){
            return null;
        }
        Employee employee = this.employeeQueue[(this.front+1)%this.maxSize];
        return employee;
    }

    /**
     * 队列是否为空
     */
    public boolean isEmpty(){
        return this.rear == this.front;
    }

    /**
     *  队列是否已满
     */
    public boolean isFull(){
        return this.rear-this.front==this.maxSize;
    }
    /**
     * 将队列的所有数据格式化显示
     */
    public String formatQueue(){
        if(isEmpty()){
            return "[]";
        }
        String str = "";
        for (int i = this.front+1;i<=this.rear ;i++){
            str += employeeQueue[i%this.maxSize]+"\n";
        }
        return str;
    }
}

优点:

  • 解决了移出数据后空间无法再次使用的问题
  • 解决了队列会出现空余位置的问题

缺点:

  • 队列容纳的数据数量有限制

链表实现队列

链表实现队列的几种情况:

链表1-1

链表1-2

链表1-3

由上面四种情况可得到以下信息:

  • 初始值last=head
  • head的next指向第一条数据,last直接指向最后一条数据
  • 判断队列为空的条件是head.next==null
  • 有效数据个数为length
  • 入队时将last.next指向新数据,再将last指向新数据
  • 出队时先保存head.next,再将head.next指向取出的数据的next
public class LinkQueue {

    public int length = 0;  //统计有效队列中的数据个数
    private Node head;  //队列的头部
    private Node last;  //队列的尾部

    public LinkQueue(){
        head = new Node();
        this.last = this.head;
    }

    /**
     *  添加一个数据,添加到尾部,添加成功返回true,失败返回false
     */
    public boolean addEmployee(Employee employee){
        Node node = new Node();
        node.data = employee;
        this.last.next = node;
        this.last = node;
        this.length ++;
        return true;
    }

    /*
     *  获取第一条数据,获取后会从队列中移除
     */
    public Employee getEmployee(){
        if(isEmpty()){
            return null;
        }
        Node temp = this.head.next;
        this.head.next = temp.next;
        length --;
        return temp.data;
    }

    /**
     *  显示第一条数据,仅显示,不会从队列移除
     */
    public Employee showEmployee(){
        if(isEmpty()){
            return null;
        }
        Node temp = this.head.next;
        return temp.data;
    }

    /**
     * 队列是否为空
     */
    public boolean isEmpty(){
        return this.head.next == null;
    }

    /**
     * 将队列的所有数据格式化显示
     */
    public String formatQueue(){
        if(isEmpty()){
            return "[]";
        }
        String str = "";
        Node temp = this.head.next;
        while (true){
            str += temp.data.toString() + "\n";
            if(temp.next==null){
                break;
            }
            temp = temp.next;
        }
        return str;
    }
    class Node{
        private Employee data;
        private Node next;
    }
}

优点:

  • 队列容量不受限制
  • 队列不会出现空余位置
  • 利用JVM的垃圾回收机制,可以合理的利用系统资源

转载于:https://my.oschina.net/rawlins/blog/3101773

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值