队列基于链表和数组的实现方法(java)

一、队列的定义

  • 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
    队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素成为出队。因为队列只允许在一段插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表。

二、队列的链表实现

  • 用链表实现队列时,应指定一个头引用和一个尾引用,头引用指向队首,尾引用指向队尾,另外增加一个元素计数器。

三、实现步骤(重点)

  • 1.定义一个结点类LinearNode.java,用于构造链表。

public class LinearNode<T> {
    //指向下一个节点
    private LinearNode<T> next;
    //本节点存储的元素
    private T element;

    /**
     * 创建一个空的节点
     */
    public LinearNode() {
        next = null;
        element = null;
    }

    /**
     * 创建一个节点存储指定元素
     * 
     * @param elem要存储的元素
     */
    public LinearNode(T elem) {
        next = null;
        element = elem;
    }

    /**
     * 返回下一个节点
     * 
     * @return 下一个节点
     */
    public LinearNode<T> getNext() {
        return next;
    }

    /**
     * 设置下一个节点
     * 
     * @param node要设置的节点
     */
    public void setNext(LinearNode<T> node) {
        next = node;
    }

    /**
     * 返回节点所指向的内容
     *  
     * @return 存储在该节点下的内容
     */
    public T getElement() {
        return element;
    }

    /**
     * 设置节点所存储的内容
     * 
     * @param elem将要存储到节点的内容
     */
    public void setElement(T elem) {
        element = elem;
    }

}
  • 2.定义队列接口,Queue.java:
public interface QueueADT<T> {
    //入队
    public void enqueue(T element);
    //出队
    public T dequeue();
    //查看队首元素
    public T first();
    //判断队是否为空
    public boolean isEmpty();
    //确定队内元素
    public int size();

}
  • 3.定义LinkedQueue.java实现QueueADT接口,并实现其所有方法。
public class LinkedQueue<T> implements QueueADT<T> {
    //元素计数器
    private int count;
    //定义一个头引用和尾引用
    private LinearNode<T> head, tail;

    public LinkedQueue() {
        count = 0;
        head = tail = null;
    }

    @Override
    /**
     * 1.从链表的末端添加元素,如果链表为空,则head引用也要设置为指向该新元素(唯一元素)
     * 2.将当前末端元素(tail引用)的next引用设置为指向新元素
     * 3.重新把tail引用设置为指向新添加的末元素
     * 4.递增元素计数器
     */
    public void enqueue(T element) {
        LinearNode<T> node = new LinearNode<>(element);

        if (isEmpty()) {
            head = node;
        } else {
            tail.setNext(node);
        }

            tail = node;
            count++;


        System.out.println("count:" + count);

    }

    @Override
    /**
     * 1.确保队列不为空
     * 2.设置一个临时引用等于栈顶元素
     * 3.设置head引用为队头元素的next引用
     * 4.递减元素计数器
     * 5.如果队列为空,将tail引用设置为null
     */
    public T dequeue() throws EmptyCollectionException {
        if (isEmpty())
            throw new EmptyCollectionException("queue");

        T result = head.getElement();

        head = head.getNext();

        count--;

        if (isEmpty())
            tail = null;

        return result;
    }

    @Override
    public T first() {

        return head.getElement();
    }

    @Override
    public boolean isEmpty() {
        if (count == 0) {
            return true;
        } else {
            return false;
        }

    }

    @Override
    public int size() {

        return count;
    }

    //遍历队内元素
    public void syso() {
        LinearNode<T> next = head.getNext();
        while (next != null) {
            System.out.println(next.getElement());
            next = next.getNext();

        }
    }

}
  • 4.定义异常类,当队为空时,抛出异常。
public class EmptyCollectionException extends RuntimeException {

    public EmptyCollectionException(String collection) {
        super("the" + collection + "is empty");
    }


}

四、队列的数组实现

  • 定义一个环形数组(即数组的最后一个索引后面跟的是第一个索引),定义一个整数值front,表示是队首首元素的存储位置;另一个整数值rear表示数组的下一个可用单元,还需定义整数值count用于元素计数。
  • 当front或rear的值到达最后一个索引时,应使它们的值变成第一个索引,可用此方法更新其值:rear = (rear + 1) % queue.length;

五、实现步骤

-定义CircularArrayQueue类实现QueueADT接口并实现其方法

public class CircularArrayQueue<T> implements QueueADT<T> {
    //数组容量
    private final int DEFAULT_CAPACITY = 100;
    // front:首元素存储的位置,rear:下一个可用单元,count:元素计数器
    private int front, rear, count;
    private T[] queue;

    /**
     * 创建一个指定容量的队列
     * 
     * @param initialCapacity
     */
    public CircularArrayQueue(int initialCapacity) {
        front = rear = count = 0;
        queue = (T[]) (new Object[initialCapacity]);

    }

    public CircularArrayQueue() {
        front = rear = count = 0;
        queue = (T[]) (new Object[DEFAULT_CAPACITY]);
    }

    @Override
    /**
     * 1.数组满时,扩充数组的容量
     * 2.入队
     * 3.正确更新rear的值
     * 4.递增元素计数器
     */
    public void enqueue(T element) {
        if (size() == queue.length) {
            expandCapacity();
        }

        queue[rear] = element;
        rear = (rear + 1) % queue.length;
        count++;

    }

    /**
     * 当数组容量不够时,扩充数组,切记,已有数组的元素必须按照其在队列中的正确顺序(而不是它们出现在数组 中的顺序)复制到新数组中。
     */
    private void expandCapacity() {
        T[] larger = (T[]) (new Object[queue.length * 2]);
        for (int scan = 0; scan < count; scan++) {
            larger[scan] = queue[front];
            front = (front + 1) % queue.length;
        }

        front = 0;
        rear = count;
        queue = larger;

    }

    @Override
    /**
     * 1.确保队列不为空
     * 2.定义一个临时变量来存储队首元素
     * 3.出列一个,将位置空出一个
     * 4.更新front的值
     * 5.递减元素计数器,返回队首元素
     */
    public T dequeue() {
        if (isEmpty()) {
            throw new EmptyCollectionException("   queue   ");
        }

        T result = queue[front];
        queue[rear] = null;
        front = (front + 1) % queue.length;
        count--;
        return result;
    }

    @Override
    public T first() {

        return queue[front];
    }

    @Override
    public boolean isEmpty() {
        if (count == 0) {
            return true;
        } else {
            return false;
        }

    }

    @Override
    public int size() {
        return count;
    }

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值