• 数组模拟队列


    数组模拟队列

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

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

      

      当将数据存入队列时称为 “addQueue”,addQueue 的处理需要有两个步骤:思路分析:

        (1)将尾指针往后移:rear+1,当 front == rear 【空】

        (2)若尾指针 rear 小于 队列的最大小标 maxSize-1,则将数据存入 rear 所指的数组元素中,否则无法存入数据。rear == maxSize-1【队列满】

      代码实现:

      1 public class ArrayQueueDemo {
      2 
      3     public static void main(String[] args) {
      4         // 测试
      5         // 创建一个队列
      6         ArrayQueue queue = new ArrayQueue(3);
      7         char key = ' '; // 接收用户输入
      8         Scanner scanner = new Scanner(System.in);
      9         boolean loop = true;
     10         
     11         // 输出一个菜单
     12         while(loop) {
     13             System.out.println("s(show):显示队列");
     14             System.out.println("e(exit):退出程序");
     15             System.out.println("a(add):添加数据到队列");
     16             System.out.println("g(get):从队列取出数据");
     17             System.out.println("h(head):查看队列头数据");
     18             
     19             key = scanner.next().charAt(0); // 接收一个字符
     20             switch (key) {
     21             case 's':
     22                 queue.showQueue();
     23                 break;
     24             case 'a':
     25                 System.out.println("输入一个数");
     26                 int value = scanner.nextInt();
     27                 queue.addQueue(value);
     28                 break;
     29             case 'g':
     30                 try {
     31                     int res = queue.getQueue();
     32                     System.out.printf("取出的数据是%d\n",res);
     33                 } catch (Exception e) {
     34                     System.out.println(e.getMessage());
     35                 }
     36                 break;
     37             case 'h':
     38                 try {
     39                     int res = queue.headQueue();
     40                     System.out.printf("队列头的数据是%d\n",res);
     41                 } catch (Exception e) {
     42                     System.out.println(e.getMessage());
     43                 }
     44             case 'e':
     45                 scanner.close();
     46                 loop = false;
     47                 break;
     48             default:
     49                 break;
     50             }
     51         }
     52         System.out.println("程序结束");
     53     }
     54 
     55 }
     56 
     57 // 使用数组模拟队列-编写一个ArrayQueue 类
     58 class ArrayQueue {
     59     private int maxSize; // 表示数组的最大容量
     60     private int front; // 指向队列头
     61     private int rear; // 指向队列尾
     62     private int[] arr; // 该数据用来存放数据,模拟队列
     63 
     64     // 创建队列的构造方法
     65     public ArrayQueue(int arrMaxSize) {
     66         maxSize = arrMaxSize;
     67         arr = new int[maxSize];
     68         front = -1; // 指向队列头部,分析出 front 是指向队列头的前一个位置
     69         rear = -1; // 指向队列尾,指向队列尾的数据(即就是队列最后一个数据)
     70     }
     71 
     72     // 判断队列是否满
     73     public boolean isFull() {
     74         return rear == maxSize - 1;
     75     }
     76 
     77     // 判断队列是否为空
     78     public boolean isEmpty() {
     79         return rear == front;
     80     }
     81 
     82     // 添加数据到队列
     83     public void addQueue(int n) {
     84         // 判断队列是否满
     85         if (isFull()) {
     86             System.out.println("队列已满,不能加入数据");
     87             return;
     88         }
     89         rear++; // 让 rear 后移
     90         arr[rear] = n;
     91     }
     92 
     93     // 获取队列的数据,出队列
     94     public int getQueue() {
     95         // 判断队列是否空
     96         if (isEmpty()) {
     97             // 通过抛出异常
     98             throw new RuntimeException("队列空,不能取数据");
     99         }
    100         front++;
    101         return arr[front];
    102     }
    103 
    104     // 显示队列的所有数据
    105     public void showQueue() {
    106         // 遍历数组
    107         if (isEmpty()) {
    108             System.out.println("队列为空,没有数据");
    109             return;
    110         }
    111 
    112         for (int i = 0; i < arr.length; i++) {
    113             System.out.printf("arr[%d]=%d\n", i, arr[i]);
    114         }
    115     }
    116 
    117     // 显示队列的头数据,不是取出数据
    118     public int headQueue() {
    119         if (isEmpty()) {
    120             throw new RuntimeException("队列为空,没有数据");
    121         }
    122         return arr[front + 1];
    123     }
    124 
    125 }
    View Code

      问题分析并优化:

        (1)目前数组使用一次就不能使用,没有达到复用的效果。

        (2)将这个数组使用算法,改进成一个环形的数组。

    数组模拟环形队列

      对前面的数组模拟队列的优化,充分利用数组,因此将数组看做是一个环形的。(通过取模的方法来实现即可)

      分析说明:

        (1)尾索引的下一个为头索引时表示队列满,即将队列容量空出一个作为约定,这个在做判断队列满的时候要注意 (real+1)%maxSize == front【满】

        (2)rear == front 【空】

        (3)分析示意图:

                      

         (4)代码实现

      1 public class CircleArrayQueue {
      2 
      3     public static void main(String[] args) {
      4         // 测试
      5         System.out.println("测试数组模拟环形队列的数据");
      6 
      7         // 创建一个环形队列
      8         CircleArray queue = new CircleArray(4); // 设置4,其最大空间为3
      9         char key = ' '; // 接收用户输入
     10         Scanner scanner = new Scanner(System.in);
     11         boolean loop = true;
     12 
     13         // 输出一个菜单
     14         while (loop) {
     15             System.out.println("s(show):显示队列");
     16             System.out.println("e(exit):退出程序");
     17             System.out.println("a(add):添加数据到队列");
     18             System.out.println("g(get):从队列取出数据");
     19             System.out.println("h(head):查看队列头数据");
     20 
     21             key = scanner.next().charAt(0); // 接收一个字符
     22             switch (key) {
     23             case 's':
     24                 queue.showQueue();
     25                 break;
     26             case 'a':
     27                 System.out.println("输入一个数");
     28                 int value = scanner.nextInt();
     29                 queue.addQueue(value);
     30                 break;
     31             case 'g':
     32                 try {
     33                     int res = queue.getQueue();
     34                     System.out.printf("取出的数据是%d\n", res);
     35                 } catch (Exception e) {
     36                     System.out.println(e.getMessage());
     37                 }
     38                 break;
     39             case 'h':
     40                 try {
     41                     int res = queue.headQueue();
     42                     System.out.printf("队列头的数据是%d\n", res);
     43                 } catch (Exception e) {
     44                     System.out.println(e.getMessage());
     45                 }
     46             case 'e':
     47                 scanner.close();
     48                 loop = false;
     49                 break;
     50             default:
     51                 break;
     52             }
     53         }
     54         System.out.println("程序结束");
     55     }
     56 
     57 }
     58 
     59 class CircleArray {
     60     private int maxSize; // 表示数组的最大容量
     61     // front 变量含义做调整:front 就指向队列的第一个元素,即 arr[front]是第一个元素
     62     // front 的初始值 = 0
     63     private int front;
     64     // rear 变量含义做调整:rear 指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定
     65     // real 的初始值 = 0
     66     private int rear; // 指向队列尾
     67     private int[] arr; // 该数据用来存放数据,模拟队列
     68 
     69     // 构造器
     70     public CircleArray(int arrMaxSize) {
     71         maxSize = arrMaxSize;
     72         arr = new int[maxSize];
     73         front = 0;
     74         rear = 0;
     75     }
     76 
     77     // 判断队列是否满
     78     public boolean isFull() {
     79         return (rear + 1) % maxSize == front;
     80     }
     81 
     82     // 判断队列是否为空
     83     public boolean isEmpty() {
     84         return rear == front;
     85     }
     86 
     87     // 添加数据到队列
     88     public void addQueue(int n) {
     89         // 判断队列是否满
     90         if (isFull()) {
     91             System.out.println("队列已满,不能加入数据");
     92             return;
     93         }
     94         // 直接将数据加入
     95         arr[rear] = n;
     96         // 将 rear 后移,这里必须取模
     97         rear = (rear + 1) % maxSize;
     98     }
     99 
    100     // 获取队列的数据,出队列
    101     public int getQueue() {
    102         // 判断队列是否空
    103         if (isEmpty()) {
    104             // 通过抛出异常
    105             throw new RuntimeException("队列空,不能取数据");
    106         }
    107         // 这里需要分析出 front 是指向队列的第一个元素
    108         // 1.先把 front 对应的值保留一个临时变量
    109         // 2.把 front 后移
    110         // 3.把临时保存的变量返回
    111         int value = arr[front];
    112         front = (front + 1) % maxSize;
    113         return value;
    114     }
    115 
    116     // 显示队列的所有数据
    117     public void showQueue() {
    118         // 遍历数组
    119         if (isEmpty()) {
    120             System.out.println("队列为空,没有数据");
    121             return;
    122         }
    123 
    124         // 从 front 开始遍历,遍历多少个元素
    125         for (int i = front; i < front + size(); i++) {
    126             System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
    127         }
    128     }
    129 
    130     // 求出当前队列有效数据的个数
    131     public int size() {
    132         return (rear + maxSize - front) % maxSize;
    133     }
    134 
    135     // 显示队列的头数据,不是取出数据
    136     public int headQueue() {
    137         if (isEmpty()) {
    138             throw new RuntimeException("队列为空,没有数据");
    139         }
    140         return arr[front];
    141     }
    142 }
    View Code
  • 相关阅读:
    C# Stream篇(—) -- Stream基类-----转载
    C# Stream篇(三) -- TextWriter 和 StreamWriter---转载
    C#文件过滤器filter---转载
    微信列表展示与详情页
    关于微信表单添加与图片上传
    登录的php代码 接口开发
    文章列表与点赞的一些功能实现 以及详情页点赞、取消赞操作
    Linux 简单命令总结
    微信小程序实现登录功能 (第一种模式)
    201509-1 数列分段 Java
  • 原文地址:https://www.cnblogs.com/niujifei/p/11550025.html
Copyright © 2020-2023  润新知