队列的实现与应用

队列是一种线性集合,其元素一端加入,从另一端删除,因此我们说队列元素是按先进先出(FIFO)方式处理。

队列的处理过程:通常队列会画成水平,其中一端作为队列的前端(front)也称队首(head),另一端作为队列的末端(rear)也称队尾(tail).元素都是从队列末端进入,从队列前端退出.

因而在队列中,其处理过程可在队列的两端进行,而在栈中,其处理过程只在栈的一端进行,但两者也有相似之处,与栈类似,队列中也没有操作能让用户“抵达”队列中部,同样也没有操作允许用户重组或删除多个元素。(不过这些操作都可以再链表中实现)

下面我们定义一个泛型QueueADT接口来表示队列的各种操作(队列的首要作用是保存顺序,而栈则相反是用来颠倒顺序)

复制代码
package xidian.sl.queue;

import xidian.sl.stack.EmptyCollectionException;

/**
 * 栈的首要作用是颠倒顺序,而队列的首要作用是保持顺序
 * */
public interface QueueADT<T> {
    /*向队列末尾添加一个元素*/
    public void enqueue(T element);
    
    /*从队列前端删除一个元素*/
    public T dequeue() throws EmptyCollectionException;
    
    /*考察队列前端的那个元素*/
    public T first();
    
    /*判断队列是否为空*/
    public boolean isEmpty();
    
    /*判定队列中的元素个数*/
    public int size();
    
    /*返回队列的字符串表示*/
    public String toString();
}
复制代码

 

与栈的实现一样,我们这里也提供两种实现方法:链表与数组的实现

1.链表实现队列:

队列与栈的区别在于,我们必须要操作链表的两端。因此,除了一个指向链表首元素的引用外,还需要跟踪另一个指向链表末元素的引用。再增加一个整形变量count来跟踪队列中的元素个数。

综合考虑,我们使用末端入列,前端出列

复制代码
package xidian.sl.queue;

import xidian.sl.stack.EmptyCollectionException;
import xidian.sl.stack.LinearNode;

public class LinkedQueue<T> implements QueueADT<T> {
    //跟踪队列中的元素个数
    private int count;
    //指向首元素末元素的引用
    private LinearNode<T> front, rear;
    
    public LinkedQueue(){
        count = 0;
        front = rear = null;
    }
    
    /**
     * 实现dequeue操作时,确保至少存在一个可返回的元素,如果没有,就要抛出异常
     * @throws EmptyCollectionException 
     * */
    public T dequeue() throws EmptyCollectionException {
        if(isEmpty()){
            throw new EmptyCollectionException("queue");
        }
        
        T result = front.getElement();
        front = front.getNext();
        count--;
        //如果此时队列为空,则要将rear引用设置为null,front也为null,但由于front设置为链表的next引用,已经有处理
        if(isEmpty()){
            rear = null;
        }
        return result;
    }

    /**
     * enqueue操作要求将新元素放到链表的末端
     * 一般情况下,将当前某元素的next引用设置为指向这个新元素,并重新把rear引用设置为指向这个新添加的末元素,但是,如果队列
     * 目前为空,则front引用也要设置为指向这个新元素
     * */
    public void enqueue(T element) {
        LinearNode<T> node = new LinearNode<T>(element);
        
        if(isEmpty()){
            front = node;
        }else{
            rear.setNext(node);
        }
        rear = node;
        count++;
    }

    @Override
    public T first() {
        T result = front.getElement();
        return result;
    }

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

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

}
复制代码

这里使用到的LinearNode类与在栈中使用到的是一样的:

复制代码
package xidian.sl.stack;

/**
 * 节点类,含有另个引用,一个指向链表的下一个LinearNode<T>节点,
 * 另一个指定本节点中存储的元素 
 * */
public class LinearNode<T> {
    /*指向下一个节点*/
    private LinearNode<T> next;
    /*本节点存储的元素*/
    private T element;
    
    /*创建一个空的节点*/
    public LinearNode(){
        next = null;
        element = null;
    }
    
    /*创建一个存储了特殊元素的节点*/
    public LinearNode(T elem){
        next = null;
        element = elem;
    }
    
    /*返回下一个节点*/
    public LinearNode<T> getNext(){
        return next;
    }
    
    /*设置下一个节点*/
    public void setNext(LinearNode<T> node){
        next = node;
    }

    /*获得当前节点存储的元素*/
    public T getElement() {
        return element;
    }
    
    /*设置当前节点存储的元素*/
    public void setElement(T element) {
        this.element = element;
    }
    
    
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值