【数据结构】—— 队列(有序队列及环形队列的数组实现)

简介: 【数据结构】—— 队列(有序队列及环形队列的数组实现)

队列的一个使用场景

我们去银行办理业务时,如果人多且假设只有四个窗口时,我们就需要排队等候,先进去的先办理,办理结束之后先出去(先进先出)

什么是队列?

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

使用数组模拟队列示意图

数组模拟队列

队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如上图, 其中 maxSize 是该队列的最大容量。


因为队列的输出、输入是分别从前后端来处理,因此需要两个变量 front及 rear分别记录队列前后端的下标,front 会随着数据输出而改变,而 rear则是随着数据输入而改变,如图所示:

                                  使用数组模拟队列示意图

实现思路:

当我们将数据存入队列时称为”addQueue”,addQueue 的处理需要有两个步骤:


(首先我们需要知道的是front和rear的初始值都为-1,都指向的是数组首元素的前一位)


1)将尾指针往后移:rear+1 , 当front == rear时 ,说明队列中还没有元素。


2)若尾指针 rear 小于队列的最大下标 maxSize-1(因为数组下标是从0开始的),则将数据存入 rear所指的数组元素中,否则无法存入数据( rear  == maxSize - 1[队列满] )


编写一个ArrayQueue类的代码实现过程

class ArrayQueue{
  private int maxSize;// 表示数组的最大容量
  private int front;// 队列头
  private int rear;// 队列尾
  private int[] arr;// 该数组用于存放数据,模拟队列
  // 创建队列的构造器
  public ArrayQueue(int arrMaxSize) {
    maxSize = arrMaxSize;
    arr = new int[maxSize];
    front = -1;// 指向队列头部,分析出front是指向队列头的前一个位置
    rear = -1;// 指向队列尾,指向队列尾的数据(即就是队列最后一个数据)
  }
}

判断队列是否满和空

  // 判断队列是否满
  public boolean isFull() {
    return rear == maxSize - 1;
  }
  // 判断队列是否空
  public boolean isEmpty() {
    return rear == front;
  }

入队出队

    // 添加数据到队列
  public void addQueue(int n) {
    // 判断队列是否满
    if (isFull()) {
      System.out.println("队列已满,不能再添加数据");
      return;
    }
    rear++;// 让rear后移
    arr[rear] = n;
  }
  // 获取队列数据,出队
  public int getQueue() {
    // 判断队列是否为空
    if (isEmpty()) {
      // 这里不能直接return,而是通过抛出异常来处理程序
      throw new RuntimeException("队列空不能取数据");
      // 这个位置不要再写代码(到不了没意义)
      // 另外需要返回值的方法,一定要给返回值或者抛出异常
    }
    front++;// front后移(因为front指向的是数组第一个元素的前一个)
    return arr[front];
  }

显示队列数据

  // 显示队列所有的数据
  public void showQueue() {
    // 遍历
    if (isEmpty()) {
      System.out.println("队列中没有数据");
      return;
    }
    for (int i = 0; i < arr.length; i++) {
      System.out.printf("arr[%d]=%d\n", i, arr[i]);
    }
  }
  // 显示队列的头数据(不是取出数据)
  public int headQueue() {
    if (isEmpty()) {
      throw new RuntimeException("队列中没有数据");
    }
    return arr[front + 1];
  }

问题

用数组模拟队列你会发现使用一次之后就不能使用了 ,没有达到复用的效果。

数组模拟环形队列

思路如下:

front 变量的含义做一个调整: front 就指向队列的第一个元素, 也就是说 arr[front] 就是队列的第一个元素 front 的初始值 = 0


rear 变量的含义做一个调整:rear 指向队列的最后一个元素的后一个位置. 因为希望空出一个空间做为约定. rear 的初始值 = 0


当队列满时,条件是  (rear  + 1) % maxSize == front 【满】


对队列为空的条件, rear == front 空


当我们这样分析, 队列中有效的数据的个数   (rear + maxSize - front) % maxSize   // rear = 1 front = 0


我们就可以在原来的队列上修改得到,一个环形队列

                                使用数组模拟队列示意图

 尾索引的下一个为头索引时表示队列满,即将队列容量空出一个作为约定,


       这个在判断队列满的时候要注意


       (rear + 1)% maxSize == front  ---> 满


          rear == front ---> 空

网络异常,图片无法展示
|

代码实现

package com.atguigu.queue;
import java.util.Scanner;
public class CircleArrayQueueDemo {
  public static void main(String[] args) {
    //测试一把
    System.out.println("测试数组模拟环形队列的案例~~~");
    // 创建一个环形队列
    CircleArray queue = new CircleArray(4); //说明设置4, 其队列的有效数据最大是3
    char key = ' '; // 接收用户输入
    Scanner scanner = new Scanner(System.in);//
    boolean loop = true;
    // 输出一个菜单
    while (loop) {
      System.out.println("s(show): 显示队列");
      System.out.println("e(exit): 退出程序");
      System.out.println("a(add): 添加数据到队列");
      System.out.println("g(get): 从队列取出数据");
      System.out.println("h(head): 查看队列头的数据");
      key = scanner.next().charAt(0);// 接收一个字符
      switch (key) {
      case 's':
        queue.showQueue();
        break;
      case 'a':
        System.out.println("输出一个数");
        int value = scanner.nextInt();
        queue.addQueue(value);
        break;
      case 'g': // 取出数据
        try {
          int res = queue.getQueue();
          System.out.printf("取出的数据是%d\n", res);
        } catch (Exception e) {
          // TODO: handle exception
          System.out.println(e.getMessage());
        }
        break;
      case 'h': // 查看队列头的数据
        try {
          int res = queue.headQueue();
          System.out.printf("队列头的数据是%d\n", res);
        } catch (Exception e) {
          // TODO: handle exception
          System.out.println(e.getMessage());
        }
        break;
      case 'e': // 退出
        scanner.close();
        loop = false;
        break;
      default:
        break;
      }
    }
    System.out.println("程序退出~~");
  }
}
class CircleArray {
  private int maxSize; // 表示数组的最大容量
  //front 变量的含义做一个调整: front 就指向队列的第一个元素, 也就是说 arr[front] 就是队列的第一个元素 
  //front 的初始值 = 0
  private int front; 
  //rear 变量的含义做一个调整:rear 指向队列的最后一个元素的后一个位置. 因为希望空出一个空间做为约定.
  //rear 的初始值 = 0
  private int rear; // 队列尾
  private int[] arr; // 该数据用于存放数据, 模拟队列
  public CircleArray(int arrMaxSize) {
    maxSize = arrMaxSize;
    arr = new int[maxSize];
  }
  // 判断队列是否满
  public boolean isFull() {
    return (rear + 1) % maxSize == front;
  }
  // 判断队列是否为空
  public boolean isEmpty() {
    return rear == front;
  }
  // 添加数据到队列
  public void addQueue(int n) {
    // 判断队列是否满
    if (isFull()) {
      System.out.println("队列满,不能加入数据~");
      return;
    }
    //直接将数据加入
    arr[rear] = n;
    //将 rear 后移, 这里必须考虑取模
    rear = (rear + 1) % maxSize;
  }
  // 获取队列的数据, 出队列
  public int getQueue() {
    // 判断队列是否空
    if (isEmpty()) {
      // 通过抛出异常
      throw new RuntimeException("队列空,不能取数据");
    }
    // 这里需要分析出 front是指向队列的第一个元素
    // 1. 先把 front 对应的值保留到一个临时变量
    // 2. 将 front 后移, 考虑取模
    // 3. 将临时保存的变量返回
    int value = arr[front];
    front = (front + 1) % maxSize;
    return value;
  }
  // 显示队列的所有数据
  public void showQueue() {
    // 遍历
    if (isEmpty()) {
      System.out.println("队列空的,没有数据~~");
      return;
    }
    // 思路:从front开始遍历,遍历多少个元素
    // 动脑筋
    for (int i = front; i < front + size() ; i++) {
      System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
    }
  }
  // 求出当前队列有效数据的个数
  public int size() {
    // rear = 2
    // front = 1
    // maxSize = 3 
    return (rear + maxSize - front) % maxSize;   
  }
  // 显示队列的头数据, 注意不是取出数据
  public int headQueue() {
    // 判断
    if (isEmpty()) {
      throw new RuntimeException("队列空的,没有数据~~");
    }
    return arr[front];
  }
}

●由于作者水平有限,文章难免存在谬误之处,敬请读者斧正,俚语成篇,恳望指教!

                                                                                ——By 作者:大耳朵宋宋

相关文章
|
19天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
98 9
|
1月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
31 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
22天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
初步认识栈和队列
初步认识栈和队列
60 10
|
1月前
|
存储 算法 定位技术
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
这篇文章主要介绍了稀疏数组和队列的概念、应用实例以及如何使用数组模拟队列和环形队列的实现方法。
21 0
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
|
1月前
【数据结构】-- 栈和队列
【数据结构】-- 栈和队列
17 0
|
1月前
探索数据结构:队列的的实现与应用
探索数据结构:队列的的实现与应用
|
1月前
|
存储 C语言
栈和队列题目练习
栈和队列题目练习
18 0
|
10天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
19 1
|
13天前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。

热门文章

最新文章

下一篇
无影云桌面