一文搞懂数据结构 之 队列和环形队列

什么是队列?

队列是一种固定大小的有序列表,它的特点是先进先出。

队列有四个重要参数,【头】【尾】【最大长度】【数据区】

在 Java 中的声明方式:

 

当队列构建完成以后,队尾和队首同时指向 地址 1 ,当向队列插入数据时,队尾向后移动,直至队尾等于 maxSize时 ((全文:队首、队尾初始值为 0),maxSize = 5) 队列已满,我们便无法再向队列插入数据 

 每当我们取出一个数据,队首就向后移动一个地址,直至 队首等于队尾,所有数据取完,队列为空。

根据上面的分析,我们可以知道,当队尾 = 队首时 队列为空,当 队尾 = maxSize 时,队列已满。

这是一个传统的队列,每当我们取出一个数据,队列的可用空间就会失去一个,也就是说,这个队列只能使用一次。

那么如何让队列空间可以重复利用呢?

循环队列它来了!循环队列是通过一定的算法,将一个线性队列看作一个环,使得这个队列空间可以重复利用的数据结构。

 循环队列,理解上可以将它理解成一个环,但它实际还是一个线性队列,只是再传统队列的基础之上通过算法,使它的空间可以重复利用。

在环形队列中,我们无法再像传统队列那样,使用队尾 = maxSize 来判断队列是否已满。

所以,为了能够判断队列是否已经存储满,我们需要浪费掉一个空间来判断是否已满。而这个空间,始终是队尾的后一个空间。而这个判断条件就是,浪费掉的空间 取模 maxSize 是否等于队首,队尾的值,始终取 队尾%maxSize

即 (rear+1)% 8 == front | rear = rear%8

为了理解,这里做出几个数据假设:

        假设 队首(front) 队尾(rear)maxSize = 8

        下表是填充数据不取出的情况

队尾(rear)浪费掉的空间(rear+1)% maxSize队首(front)队列是否已满(T/F)
010F
120F
230F
................
70     ( 8 % 8)0T

     填充,并取出两个数据即 队首 = 2 (取出0,1两个地址的数据后,队首的位置)

      

队尾(rear)浪费掉的空间(rear+1)% maxSize队首(front)队列是否已满(T/F)
702F
81 ( 8+1 = 9 % 8 )2F
2 (1+1 = 2 % 8)2T

     ok,我们总结一下,传统队列和循环队列,空,满时的条件

传统队列front = rear rear = maxSize
循环队列front = rear front = (rear+1)%maxSize

        在传统队列中,队首和队尾的取值最大为maxSize ,而循环队列中,队首和队尾的取值都是在 %maxSize 进行一个循环 即(rear % 8 ,front%8)

最后:书写不易,多多支持!附上代码:

传统队列

package com.uxteam.data;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/*
*  队列: 队列是一种先进先出的线性表,他只允许从尾部插入数据,头部删除数据,通常由链表或数组实现
*
* */
public class ArrayQueue {
    // 队列的最大长度
    private int maxSize;
    // 队列头部位置
    private int front;
    // 队列尾部位置
    private int rear;
    // 队列数据存储区域
    private int[] data;

    public ArrayQueue(int maxSize){
        init(maxSize);
    }
    // 初始化队列数据
    private void init(int maxSize){
        this.maxSize = maxSize;
        this.front = 0;
        this.rear = 0;
        this.data = new int[maxSize];
    }

    /**
     * 判断队列是否为空
     * @return true / false
     */
    // todo 判断队列是否为空 -- 完成
    public boolean isEmpty(){
        return rear - front == 0;
    }

    /***
     * 判断队列是否已满
     * @return true / false
     */
    // todo 判断队列是否已满 -- 完成
    public boolean isFull(){
        return rear == maxSize;
    }
    // todo 向队列插入元素 -- 完成
    public void insert(int ele){
        // 如果队列已满,抛出异常
        if (isFull()){
            throw new RuntimeException("队列已满");
        }
        this.data[rear++] = ele;
    }
    // todo 从队列删除元素 -- 完成
    public int remove(){
        // 如果队列是空,抛出异常
        if (isEmpty()){
            throw new RuntimeException("队列为空");
        }
        return this.data[front++];
    }
    // todo 显示队列所有元素 -- 完成
    public void list(){
        List<Integer> collect = Arrays.stream(this.data).boxed().collect(Collectors.toList());
        System.out.println(collect.subList(front,rear));
    }
    // todo 显示队列头部元素 -- 完成
    public int first(){
        if (isEmpty()){
            throw new RuntimeException("队列为空");
        }
        return this.data[front];
    }
}

循环队列

package com.uxteam.data;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class CircleQuque {
    /***
     * 环形队列最大容量
     */
    private int maxSize;
    /***
     * 队首位置
     */
    private int front;
    /***
     * 队尾位置
     */
    private int rear;
    /***
     * 数据区
     */
    private int[] data;

    /***
     * 队列构造器
     * @param maxSize 队列最大容量
     */
    public CircleQuque(int maxSize){
        init(maxSize);
    }

    /***
     * 初始化内部参数
     * @param maxSize 队列最大容量
     */
    private void init(int maxSize){
        this.maxSize = maxSize;
        this.front = 0;
        this.rear = 0;
        this.data = new int[maxSize];
    }
    // todo 判断队列是否为空

    /***
     * 判断队列是否为空
     * @return true / false
     */
    public boolean isEmpty(){
        return front == rear;
    }
    // todo 判断队列是否已满

    /***
     * 判断队列是否已满
     * @return true / false
     */
    public boolean isFull(){
        return (rear+1)%maxSize == front;
    }
    // todo 向队列添加元素

    /***
     * 向队列添加元素
     * @param ele 要添加的元素
     */
    public void insert(int ele){
        // 判断队列是否已满
        if (isFull()){
            System.out.println("队列已满!");
            return;
        }
        // 插入元素,队尾后移
        this.data[rear] = ele;
        rear = (rear+1) % maxSize;
    }
    // todo 从队列取出元素

    /***
     * 从队列取出元素
     * @return 取出的元素
     */
    public int remove(){
        // 判断队列是否为空
        if (isEmpty()){
            throw new RuntimeException("队列为空");
        }
        // 返回队首数据,队首后移
        int remove = this.data[front];
        front = (front+1) % maxSize;
        return remove;

    }
    // todo 显示队列中所有元素

    /***
     * 显示队列中所有元素
     */
    public void list(){
        List<Integer> collect = Arrays.stream(this.data).boxed().collect(Collectors.toList());
        if (rear < front){
            System.out.println(collect.subList(0,rear));
            System.out.println(collect.subList(front,maxSize));
        }else {
            System.out.println(collect.subList(front,rear));
        }

    }
    // todo 显示队列首元素

    /***
     * 显示队列首元素
     * @return 队列首元素
     */
    public int first(){
        // 判断队列是否为空
        if (isEmpty()){
            throw new RuntimeException("队列为空");
        }
        return this.data[front];
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值