0%

【数据结构和算法】队列

数据结构之队列的介绍和代码实现


1 队列

1.1 介绍

  • 队列是一个有序列表,可以用数组或是链表来实现
  • 遵循先入先出的原则,即:先存入队列的数据,要先取出;后存入队列的数据,要后取出。

1.2 思路

  • 队列添加数据:rear队尾往后移,+1
  • 队列取出数据:font队头往后移,+1
  • 队列为空:font == rear
  • 队列已满:rear == 数组大小

1.3 简单代码实现

  • (1)创建队列类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    public class NormalQueue {

    private int size; //队列长度
    private int font; //队头
    private int rear; //队尾
    private int[] queue; //队列

    public NormalQueue(int size) {
    this.size = size;
    queue = new int[size];
    font = -1;
    rear = -1;
    }

    /**
    * 向队列添加数据
    * @param data 数据
    */
    public void addData(int data) {
    if(rear == size-1) {
    System.out.println("队列已满,不能添加数据!");
    }else {
    rear ++;
    queue[rear] = data;
    }
    }

    /**
    * 从获取队列数据
    * @return int
    */
    public int getData() {
    if(font == rear) {
    System.out.println("队列为空,没有数据可取!");
    return 0;
    }else {
    font ++;
    return queue[font];
    }
    }

    /**
    * 打印队列
    */
    public void printQueue() {
    if(font != rear) {
    System.out.println("当前队列为:");
    for(int i = font + 1; i<= rear; i++) {
    System.out.println(queue[i]);
    }
    }else {
    System.out.println("队列为空!");
    }
    }
    }
  • (2)测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    public static void main(String[] args) {
    //简单队列测试
    //1、创建队列
    NormalQueue normalQueue = new NormalQueue(3);

    //2、测试打印空队列
    System.out.println("----测试打印空队列----");
    normalQueue.printQueue();

    //3、添满队列
    normalQueue.addData(1);
    normalQueue.addData(2);
    normalQueue.addData(3);
    System.out.println("----打印满队列数据----");
    normalQueue.printQueue();

    //4、测试队列已满添加数据
    System.out.println("----测试队列已满添加数据----");
    normalQueue.addData(4);

    //5、测试取出数据后队列变化
    System.out.println("----取出数据后的队列----");
    normalQueue.getData();
    normalQueue.printQueue();

    //6、取出数据后再次添加数据
    System.out.println("--取出数据后再次添加数据--");
    normalQueue.addData(4);
    }

1.4 个人环形队列代码实现

  • 此环形队列的实现为个人思路,非官方标准答案
  • 我们可以新增一个变量来记录空数据的个数,如果个数为0,就表示数据已满,不能插入;个数不为0,则可以插入
  • (1)创建环形队列类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    public class CircularQueue {

    private int size; //队列大小
    private int emptyCount; //空数据个数
    private int font; //队头
    private int rear; //队尾
    private int[] queue; //队列

    public CircularQueue(int size) {
    this.size = size;
    emptyCount = size;
    font = -1;
    rear = -1;
    queue = new int[size];
    }

    /**
    * 向队列添加数据
    * @param data 数据
    */
    public void addData(int data) {
    if(emptyCount == 0) {
    System.out.println("队列已满,不能添加数据!");
    }else {
    //判断队尾是否移动到数组尾部,是就将其设置回数组头部
    if(rear == size-1) {
    rear = 0;
    }else {
    rear ++;
    }
    emptyCount --; //空数据-1
    queue[rear] = data;
    }
    }

    /**
    * 从队列中获取数据
    * @return int
    */
    public int getData() {
    if(emptyCount == size) {
    System.out.println("队列为空,没有数据可取!");
    return 0;
    }else {
    //判断队头是否移动到数组尾部,是就将其设置回数组头部
    if(font == size-1) {
    font = 0;
    }else {
    font ++;
    }
    emptyCount ++; //空数据+1
    return queue[font];
    }
    }

    /**
    * 打印队列
    */
    public void printQueue() {
    //判断是否为空
    if(emptyCount != size) {
    //比较队头和队尾的值
    if(font < rear) {
    //队头<队尾,队列在(队头,队尾]之间
    System.out.println("当前队列为:");
    for (int i=font+1; i<=rear; i++) {
    System.out.println(queue[i]);
    }
    }else{
    //队头>=队尾,队列在(队头, size) 和 [0, rear]之间
    System.out.println("当前队列为:");
    for(int i=font+1; i<size; i++) {
    System.out.println(queue[i]);
    }
    for (int i=0; i<=rear; i++) {
    System.out.println(queue[i]);
    }
    }
    }else {
    System.out.println("队列为空!");
    }
    }
    }
  • (2)测试
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public static void main(String[] args) {
    //环形队列测试(重点测试取出数据后,再添加数据)
    //1、创建环形队列并添满数据
    CircularQueue circularQueue = new CircularQueue(3);
    circularQueue.addData(1);
    circularQueue.addData(2);
    circularQueue.addData(3);
    circularQueue.printQueue();

    //2、取出数据再添加
    circularQueue.getData();
    circularQueue.addData(4);
    circularQueue.printQueue();
    }

1.5 标准环形队列代码实现

  • (1)思路
  • 取模(取余数),我们希望队头/队尾到达数组底部的时候通过取数组大小的余数返回数组开头
  • 将队头指向该为第一个数据的下标,将队尾指向最后一个数据的下标+1
  • 但取模会出现一个问题,即0 % 任何数都为0,所以我们取余数时要 + 1,来避开0,所以整体大小+1
  • 队列中数据个数:(rear + size - font) % size
  • 队列满条件:(rear + size - font ) % size == size,可以简化为(rear + 1) % size == font
  • 队列为空条件:font == rear
  • (2)实现代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    public class CircularQueue {

    private int size; //队列长度(比输入个数多1长度作为预留空间)
    private int font; //队首(第一个元素index)
    private int rear; //队尾(最后一个元素index+1)
    private int[] queue; //队列(创建时多创一个空间作预留)

    public CircularQueue(int size) {
    this.size = size + 1;
    font = 0;
    rear = 0;
    queue = new int[size + 1];
    }

    /**
    * 向队列添加数据
    * @param data 数据
    */
    public void addData(int data) {
    if((rear+1)%size == font) {
    System.out.println("队列已满,无法添加数据!");
    }else {
    queue[rear] = data;
    rear = (rear+1) % size;
    }
    }

    /**
    * 从队列中取出数据
    * @return int
    */
    public int getData() {
    if((font == rear)) {
    System.out.println("队列为空,没有数据可取!");
    return 0;
    }else {
    int data = queue[font];
    font = (font + 1) % size;
    return data;
    }
    }


    /**
    * 打印队列
    */
    public void printQueue() {
    if(font == rear) {
    System.out.println("队列为空!");
    }else {
    System.out.println("当前队列为:");
    for(int i=font; i < font + (rear + size - font) % size; i++) {
    System.out.println(queue[i % size]);
    }
    }
    }
    }