数据结构与算法学习总结(四)——队列

基本介绍

与栈相对,队列是一种先进先出(First In First Out)的线性表,操作的规则是按照到达的顺序来释放元素,所有的插入在表的一端进行,而所有的删除都在表的另一端进行。

主要元素

队头(front)

队尾(rear)

主要操作

入队列(enQueue)

出队列(deQueue)

取队首元素(getFront)

判断队列是否为空

抽象数据类型

语言仍然采用Java

package top.zhanglugao.queue;

/***
 * 队列抽象数据类型
 * @param <T>
 */
public interface Queue<T> {
    void clear();                       //清空队列
    boolean enQueue(T t);               //入队
    T deQueue();                        //出队
    T getFront();                       //获取队首元素
    boolean isEmpty();                  //判断队列是否为空
    boolean isFull();                   //判断队列是否已满
}

实现方式

队列跟栈一样也采用顺序和链式两种方式来实现。采用顺序队列时要注意防止队列的假溢出(下面会详细解释),链式队列采用单链表方式存储,队列中每个元素对应链表中的一个结点。

顺序队列

对于顺序队列很简单的一个想法就是内部维护一个数组,再维护两个int型的变量front与rear标识队列的头与尾,元素入队从尾部进入队列后real++,元素出队时从头部弹出后front++。这种情况下队列就会发生假溢出现象,随着real继续增加到队列的maxSize-1,队列就满了不能再添加元素,但元素出队后0-front的位置其实并没有存储元素,这部分空间没法使用了,就发生假溢出现象。解决方案是做成循环数组,继续利用0-front的这部分空间。

package top.zhanglugao.queue;

public class ArrayQueue<T> implements Queue<T> {

    private int maxSize;
    private int front;
    private int rear;
    private T[] st;

    /***
     * 构造函数,顺序队列初始化时需要指定大小 让存储元素的数组多预留一个空位
     */
    public ArrayQueue(int size){
        maxSize=size+1;
        front=1;
        rear=0;
        st= (T[]) new Object[maxSize];
    }

    /***
     * 清空队列,跟重新初始化一样
     */
    public void clear() {
        front=1;
        rear=0;
    }

    /***
     * 数据入队
     * @param t
     * @return
     */
    public boolean enQueue(T t) {
        //先判断队列是否已满
        if(isFull()){
            System.out.println("队列已满");
            return false;
        }
        rear=(rear+1)%maxSize;//寻找下一个空位,环形结构 所以需要%maxSize
        st[rear]=t;
        return true;
    }

    /***
     * 数据出队,如果front=rear,队列中无元素
     * @return
     */
    public T deQueue() {
        if(isEmpty()){
            System.out.println("空队列");
            return null;
        }
        T t=getFront();
        front=(front+1)%maxSize;//环形增加
        return t;
    }

    public T getFront() {
        if(isEmpty()){
            System.out.println("空队列");
            return null;
        }
        T t=st[front];
        return t;
    }

    public boolean isEmpty() {
        if((maxSize+(rear-front+1))%maxSize==0) return true;
        return false;
    }

    public boolean isFull() {
        //还剩一个空位时就要报满
        if((rear+2)%maxSize==front)return true;
        return false;
    }

    public static void main(String[] args) {
        ArrayQueue<Integer> queue=new ArrayQueue<Integer>(3);
        queue.enQueue(1);
        queue.enQueue(2);
        queue.enQueue(3);

        System.out.println("报满---");
        queue.enQueue(4);//这句会报队列已满
        System.out.println("结束---");

        Integer integer = queue.deQueue();//弹出了一个
        System.out.println("取队列数据应该为1:"+integer);
        Integer front = queue.getFront();
        System.out.println("弹出一个后再调用getFront结果应该为2:"+front);

        System.out.println("继续添加不应该报满---");
        queue.enQueue(4);//这句不会报队列已满
        System.out.println("继续添加不应该报满检测结束---");


        System.out.print("应该输出队列满");
        System.out.println(queue.isFull());

        System.out.println("接下来依次将数据移除");
        System.out.println(queue.deQueue());
        System.out.println(queue.deQueue());
        System.out.println(queue.deQueue());

        System.out.println(queue.isEmpty());

        queue.enQueue(1);
        queue.enQueue(1);
        queue.enQueue(1);
        queue.enQueue(1);


    }
}

输出结果如下:

报满---
            队列已满
            结束---
            取队列数据应该为1:1
            弹出一个后再调用getFront结果应该为2:2
            继续添加不应该报满---
            继续添加不应该报满检测结束---
            应该输出队列满true
            接下来依次将数据移除
            2
            3
            4
            true

链式队列

链式队列采用单链表的结构,链接指针的方向是从队列的前端向尾端相连。

类定义

链式比较好理解,直接上代码。

package top.zhanglugao.queue;

import top.zhanglugao.stack.Link;

public class LinkedQueue<T> implements Queue<T> {

    private int size;
    private Link<T> front;
    private Link<T> rear;

    public void clear() {

    }

    /***
     * 将t插入队尾
     * @param t
     * @return
     */
    public boolean enQueue(T t) {
        if(rear==null){
            front=rear=new Link<T>(t,null);
        }
        else{
            rear.setNext(new Link<T>(t,null));
            rear=rear.getNext();
        }
        size++;
        return true;
    }

    public T deQueue() {
        if(size==0){
            System.out.println("队列为空");
            return null;
        }
        T t=front.getData();
        front=front.getNext();
        if(front==null){
            rear=null;
        }
        size--;
        return t;
    }

    public T getFront() {
        if(size==0){
            System.out.println("队列为空");
            return null;
        }
        T t=front.getData();
        return t;
    }

    public boolean isEmpty() {
        return size==0;
    }

    public boolean isFull() {
        return true;
    }

    public static void main(String[] args) {
        LinkedQueue<Integer> queue=new LinkedQueue<Integer>();
        queue.enQueue(1);
        queue.enQueue(2);
        queue.enQueue(3);
        queue.enQueue(4);

        System.out.println(queue.deQueue());
        System.out.println(queue.deQueue());
        System.out.println(queue.deQueue());
        System.out.println(queue.deQueue());

        System.out.println(queue.isEmpty());
    }
}

顺序队列与链式队列的比较

顺序队列需要指定存储空间,链式队列可以更好的满足大小无法估计的情况,都不允许访问队列内容元素。时间复杂度都为O(1)

队列的应用

只要满足先来先服务特性的应用均可采用队列,例如:

消息缓冲器

邮件缓冲器

操作系统的资源管理

宽度优先搜索

计算机硬设备之间的通信也需要队列作为数据缓冲

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值