数据结构-队列的Java实现(顺序结构与链结构)

目录:

1.队列的特点

队列(queue)是只允许在表的一端进行插入,在另一端进行删除的线性表。允许插入的一端叫做队尾(rear),允许删除的一端叫做队头(front)。
与栈相反,对列就是对日常生活中“先进先出”这一现象的抽象,能够帮助我们将许多实际问题抽象成数据结构来解决问题,比如操作系统对作业的排队。
队列示意图

2.队列的抽象数据类型(ADT)

将队列的操作抽象为一个接口,规范后续的顺序队列与链队列,包括队列空的判定、队列的长度、取队头元素、入队列、出队列以及队列的遍历。

public interface MyQueue {
    public void clearQueue();
    public boolean isEmpty();
    public int queueLength();
    public ElemType getHead();
    public void enQueue(ElemType e) throws Exception;
    public void deQueue() throws Exception;
    public void traverse();
}

备注:队列的数据元素,以及链队列的结点如图:
详细代码请见

数据元素和结点

3.顺序队列的实现

3.1顺序队列的存储结构与初始化

与顺序表一样,顺序队列用规定大小的ElemType数组来存储数据,存取时,以队列头front 队列尾rear 为下标进行操作。

但这样的队列结构存在一定的问题,当出现队列尾部最后一个位置被占用时,新元素无法入队列,但此时,队列可能还未满,形成“假溢出”
在这里插入图片描述
要解决这个问题,比较好的方法是将顺序队列变成一个环状的空间,也即“循环队列”。头、尾指针以及队列元素之间的关系不变,只是在循环队列中,头尾在插入删除时的自增过程要在取一次模,这样,头尾就能在顺序空间内实现头尾相接,循环移动。
在这里插入图片描述
但现在又有了新的问题,在大小为maxSize的环状空间上,以下两种情况:

  1. 队空
  2. 队满

都会导致 front == rear,这样我们便无法通过头尾指针是否相同来判断出队列的实际情况。

解决办法也很简单,有两种思路:

  1. 少用一个元素空间,即队列空间为 maxSize 时,有 maxSize-1 个元素时就认为队满,不能再插入元素。这样,判断条件不变。
  2. 另设一个标记位区别队列是“空”还是“满”。

本文将采用第一种思路设计队列。

初始化时,调用含参构造方法,初始化以maxSize为最大长度的顺序队列。

public class SqQueue implements MyQueue {
    private ElemType[] sqQueue;
    private int maxLength;
    private int front=0;
    private int rear=0;
    public SqQueue(int maxSize){
        sqQueue=new ElemType[maxSize+1];//
        maxLength=maxSize;
    }
    /*队列相关方法见下文*/
}
3.2顺序队列的入队和出队

入队:
在这里插入图片描述

    @Override
    public void enQueue(ElemType e) throws Exception{
        if((rear+1)%maxLength==front){
            throw new Exception("顺序队列满了");
        }
        sqQueue[rear]=e;
        rear=(rear+1)%maxLength;
    }

出队:
在这里插入图片描述

    @Override
    public void deQueue() throws Exception{
        if(rear==front){
            throw new Exception("顺序已空");
        }
        front=(front+1)%maxLength;
    }
3.3顺序队列的其他方法

队列空的判断、清空队列、队列内数据的长度以及队列的遍历代码如下:

    @Override
    public void clearQueue() {
        front=rear;
    }

    @Override
    public boolean isEmpty() {
        return front==rear;
    }

    @Override
    public int queueLength() {
        int k=rear-front;
        if(k>=0){
            return k;
        }
        else{
            return maxLength+k;
        }
    }

    @Override
    public ElemType getHead() {
        return sqQueue[front];
    }
    
    @Override
    public void traverse() {
        for(int i=front;(i%maxLength)!=rear;i++){
            System.out.print(sqQueue[i]+"  ");
        }
        System.out.println();
    }

4.链队列的实现

与链表一样,链队列用一个LinkNode结点来存储数据。一个链队显然需要分别指示队头和队尾才能确定,为了操作方便,给链队添加一个头结点,并令指针始终指向头结点。

链队列的操作即为链表操作的特殊情况,只是需要进一步修改头指针或者尾指针。(可以参考链表的Java实现

public class LinkQueue implements MyQueue {
    LinkNode linkQueue = new LinkNode();

    @Override
    public void clearQueue() {
        linkQueue.setNext(null);
    }

    @Override
    public boolean isEmpty() {
        return linkQueue.getNext() == null;
    }

    @Override
    public int queueLength() {
        LinkNode p = linkQueue;
        int i;
        for (i = 0; p.getNext() != null; i++) {
            p = p.getNext();
        }
        return i;
    }

    @Override
    public ElemType getHead() {
        return linkQueue.getNext().getE();
    }

    @Override
    public void deQueue() throws Exception {
        LinkNode p = linkQueue.getNext();
        linkQueue.setNext(p.getNext());
    }

    @Override
    public void traverse() {
        System.out.print("当前链队列:");
        LinkNode p = linkQueue.getNext();
        System.out.print(p.getE().toString());
        p = p.getNext();
        while (p != null) {
            System.out.print(" -> ");
            System.out.print(p.getE().toString());
            p = p.getNext();
        }
        System.out.println();
    }

    @Override
    public void enQueue(ElemType e) throws Exception {
        LinkNode p = linkQueue;
        LinkNode x=new LinkNode(e);
        while (p.getNext() != null) {
            p = p.getNext();
        }
        p.setNext(x);
    }
}

5.测试代码

class QueueTest{
    public static void main(String[] args) {
        ElemType elem1 = new ElemType("王", 1);
        ElemType elem2 = new ElemType("张", 2);
        ElemType elem3 = new ElemType("李", 3);
        ElemType elem4 = new ElemType("李", 4);
        ElemType elem5 = new ElemType("赵", 5);

        System.out.println("/---创建顺序队列---/");
        SqQueue sqQueue=new SqQueue(3);
        System.out.println("是否为空:"+sqQueue.isEmpty());
        System.out.println();
        System.out.println("/---进队列---/");
        try {
            sqQueue.enQueue(elem1);
        }
        catch (Exception e){
            System.out.println(e);
        }
        sqQueue.traverse();
        try {
            sqQueue.enQueue(elem2);
        }
        catch (Exception e){
            System.out.println(e);
        }
        sqQueue.traverse();
        System.out.println();
        System.out.println("/---出队列---/");
        try {
            sqQueue.deQueue();
        }
        catch (Exception e){
            System.out.println(e);
        }
        sqQueue.traverse();
        System.out.println();
        System.out.println("/---进队列过多---/");
        try {
            sqQueue.enQueue(elem3);
        }
        catch (Exception e){
            System.out.println(e);
        }
        sqQueue.traverse();
        try {
            sqQueue.enQueue(elem4);
        }
        catch (Exception e){
            System.out.println(e);
        }
        sqQueue.traverse();
        try {
            sqQueue.enQueue(elem4);
        }
        catch (Exception e){
            System.out.println(e);
        }

        System.out.println();
        System.out.println("/---清理队列---/");
        sqQueue.clearQueue();
        sqQueue.traverse();

        System.out.println("/---创建链队列---/");
        LinkQueue linkQueue=new LinkQueue();
        System.out.println("是否为空:"+sqQueue.isEmpty());
        System.out.println();
        System.out.println("/---进队列---/");
        try {
            linkQueue.enQueue(elem1);
        }
        catch (Exception e){
            System.out.println(e);
        }
        linkQueue.traverse();
        try {
            linkQueue.enQueue(elem2);
        }
        catch (Exception e){
            System.out.println(e);
        }
        linkQueue.traverse();
        System.out.println();
        System.out.println("/---出队列---/");
        try {
            linkQueue.deQueue();
        }
        catch (Exception e){
            System.out.println(e);
        }
        linkQueue.traverse();
        System.out.println();
        System.out.println("/---进队列过多---/");
        try {
            linkQueue.enQueue(elem3);
        }
        catch (Exception e){
            System.out.println(e);
        }
        linkQueue.traverse();
        try {
            linkQueue.enQueue(elem4);
        }
        catch (Exception e){
            System.out.println(e);
        }
        linkQueue.traverse();
        try {
            linkQueue.enQueue(elem4);
        }
        catch (Exception e){
            System.out.println(e);
        }

        System.out.println();
        System.out.println("/---清理队列---/");
        linkQueue.clearQueue();
        linkQueue.traverse();
    }
}

部分结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值