数组模拟队列

  队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图。其中,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

 

posted on 2019-09-19 15:34  格物致知_Tony  阅读(314)  评论(0编辑  收藏  举报