队列

队列是只能在一端进行插入,一端进行删除的线性表。允许插入的一端称为队尾,允许删除的一端为队头。跟我们平常排队买东西是一样的,后来者要插入时只能排在队尾,买完东西的人是从队头出去的(删除)。因为队列中队尾和队头都可以进行操作,所以定义两个指针,front指针指向队头元素,rear指针指向队尾元素的下一个位置。

既然队列也是线性表,那么也分顺序存储结构和链式存储结构。在队列的顺序存储结构中,在队头进行删除元素的操作,在队尾插入元素,可能导致分配的数组空间浪费很大一部分内存,很不明智,因此出现了循环队列。循环队列是指队列头尾相接的顺序存储结构。当队列为空时,front=rear;当队列满时,数组中还有一个空闲单元。

当rear>front时,也就是队尾指针指向的数组下标大于队头指针指向的数组下标,此时队列的长度为rear-front;当rear<front时,此时队列的长度为rear-front+QueSize;所以队列的长度的通用计算公式为(rear-front+QueSize)%QueSize。

一.顺序存储结构

1.队列的结构定义

代码实现:

class SqQueue{
    int maxSize=8;
    Object[] array=new Object[maxSize];
    int front;
    int rear;
}

2.初始化一个空循环队列

代码实现:

public static void initQueue(SqQueue sq){
    sq.front=0;
    sq.rear=0;
}

3.计算队列的长度

代码实现:

public static int calculateLength(SqQueue sq){
    int length=(sq.rear-sq.front+sq.maxSize)%sq.maxSize;
    return length;
}

4.循环队列的入队列操作

算法思路:
    1. 判断队列是否满,队列已满的判定条件为队列中还有一个空闲单元,%QueSize是考虑到队列的最后一个位置,如果直接rear+1则指针溢出队列,而求余则将指针指向队头第一个位置;
    2. 队尾(即rear指针指向的位置)插入元素;
    3. rear指针向后移一位,%QueSize原因如1;

代码实现:

public static void EnQueue(SqQueue sq,Object e){
    //判断队列是否满
    if((sq.rear+1)%sq.maxSize==sq.front){
        System.out.println("队列已满");
    }else{
        //队尾插入元素e
        sq.array[sq.rear]=e;
        //队尾指针向后移一位
        sq.rear=(sq.rear+1)%sq.maxSize;
    }
}

5.循环队列的出队列操作

算法思路:
    1. 判断队列是否为空,队列为空的判定条件为rear==front;
    2. front指针后移一位;

代码实现:

public static void DeQueue(SqQueue sq){
    //判断队列是否为空队列
    if(sq.rear==sq.front){
        System.out.println("队列为空");
    }else{
        //队头元素赋值给e
        Object e=sq.array[sq.front];
        //指针后移一位
        sq.front=(sq.front+1)%sq.maxSize;
    }
}

完整代码:

package com.java.Queue;

import java.util.Arrays;

public class QueueTest {
    static SqQueue sq=new SqQueue();
    
    public static void main(String[] args){
        EnQueue(sq,"A");
        EnQueue(sq,"B");
        EnQueue(sq,"C");
        EnQueue(sq,"D");
        DeQueue(sq);
        DeQueue(sq);
        System.out.println(sq);
        System.out.println(calculateLength(sq));
    }
    //循环队列的出队列操作
    public static void DeQueue(SqQueue sq){
        //判断队列是否为空队列
        if(sq.rear==sq.front){
            System.out.println("队列为空");
        }else{
            //队头元素赋值给e
            Object e=sq.array[sq.front];
            sq.array[sq.front]=null;
            //指针后移一位
            sq.front=(sq.front+1)%sq.maxSize;
        }
    }
    //循环队列的入队列操作
    public static void EnQueue(SqQueue sq,Object e){
        //判断队列是否满
        if((sq.rear+1)%sq.maxSize==sq.front){
            System.out.println("队列已满");
        }else{
            //队尾插入元素e
            sq.array[sq.rear]=e;
            //队尾指针向后移一位
            sq.rear=(sq.rear+1)%sq.maxSize;
        }
    }
    //计算循环队列的长度
    public static int calculateLength(SqQueue sq){
        int length=(sq.rear-sq.front+sq.maxSize)%sq.maxSize;
        return length;
    }
    //初始化一个空循环队列
    public static void initQueue(SqQueue sq){
        sq.front=0;
        sq.rear=0;
    }
}
class SqQueue{
    int maxSize=8;
    Object[] array=new Object[maxSize];
    int front;
    int rear;
    @Override
    public String toString() {
        return "SqQueue [maxSize=" + maxSize + ", array=" + Arrays.toString(array) + ", front=" + front + ", rear="
                + rear + "]";
    }
}

二.链式存储结构

队列的链式存储结构和单链表差不多,只不过之只能在队尾插入元素在队头删除元素。还有一个区别是链式存储结构中队头指针指向的是队列的头结点,队尾指针指向队尾结点;而在顺序存储结构中,队头指针指向队列的队头元素,而队尾指针指向队尾元素的下一结点。队列的链式存储结构也是不需要事先分配内存空间的。

1.链式队列结点

class QNode{
    Object data;
    QNode next;
    public QNode(Object data,QNode next){
        this.data=data;
        this.next=next;
    }
    @Override
    public String toString() {
        return "QNode [data=" + data + ", next=" + next + "]";
    }
}

2.初试化空队列,空队列时front和rear都指向头结点

class LinkQueue{
    static QNode front=new QNode("头结点",null);
    QNode rear=front;
}

3.入队操作(尾进)

    1. 将新结点赋值给队尾指针的下一个元素;
    2. 将队尾指针重新指向新结点;

代码实现:

public static void EnLinkQueue(LinkQueue lq,QNode node){
    lq.rear.next=node;
    lq.rear=node;
}

4.出队操作(头出)
    1. 先判断队列栈中是否有元素;
    2. 若非空栈,头结点后移一位;
    3. 如果头结点之后的结点为要出栈的元素,rear指向front;

代码实现:

public static void DeLinkQueue(LinkQueue lq){
    //先判断队列栈中是否有元素
    if(lq.front==lq.rear){
        System.out.println("空栈");
    }else{
        //要出栈的元素
        QNode p=lq.front.next;
        //头结点后移一位
        lq.front.next=p.next;
    }
    //如果头结点之后的结点为要出栈的元素,rear指向front
    if(lq.rear==lq.front.next){
        lq.rear=lq.front;
    }
}

完整代码:

package com.java.Queue;

public class LinkQueueTest {
    static QNode node=new QNode("A",null);
    static QNode node1=new QNode("B",null);
    static LinkQueue lq=new LinkQueue();
    public static void main(String[] args){
        EnLinkQueue(lq,node);
        System.out.println(lq.rear);
        EnLinkQueue(lq,node1);
        System.out.println(lq.rear);
        DeLinkQueue(lq);
        System.out.println(lq.front.next);
    }
    //出队操作(头出)
    public static void DeLinkQueue(LinkQueue lq){
        //先判断队列栈中是否有元素
        if(lq.front==lq.rear){
            System.out.println("空栈");
        }else{
            //要出栈的元素
            QNode p=lq.front.next;
            //头结点后移一位
            lq.front.next=p.next;
        }
        //如果头结点之后的结点为要出栈的元素,rear指向front
        if(lq.rear==lq.front.next){
            lq.rear=lq.front;
        }
    }
    //入队操作(尾进)
    public static void EnLinkQueue(LinkQueue lq,QNode node){
        lq.rear.next=node;
        lq.rear=node;
    }
}
//初始化空队列,空队列时front和rear都指向头结点
class LinkQueue{
    static QNode front=new QNode("头结点",null);
    QNode rear=front;
}

class QNode{
    Object data;
    QNode next;
    public QNode(Object data,QNode next){
        this.data=data;
        this.next=next;
    }
    @Override
    public String toString() {
        return "QNode [data=" + data + ", next=" + next + "]";
    }
}

 



posted @ 2019-01-13 13:27  考拉熊_12  阅读(343)  评论(0编辑  收藏  举报