H__D  

一、队列的介绍

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

二、用数组模拟队列思路

  1、队列是有序的,若使用数组的结构来存储队列的数据,首先要用 maxsize 来指定队列的最大容量。

  2、因为队列的输出、输入是分别从前后端来处理,因此需要两个变量 front 及 rear 分别记录队列前后端的下标,front 会随着数据输出而改变,而 rear 则是随着数据输入而改变,如果用C语言中的指针描述就是队首指针与队尾指针。

三、数组模拟队列图示  

  

四、使用java语言描述队列

4.1 java代码如下:

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

4.2 问题分析并优化

  1、目前数组使用一次就不能用,没有达到服用的效果

  2、将这个数组使用算法,改进成一个环形的队列,取模:% 

五、环形队列的介绍

  可以将队列空间想象成一个 环形空间 ,这能使队列空间重复使用:无论插入还是删除,front(队头) 增1或 rear(队尾) 加1时超出所分配的空间,就让它指向这片连续空间的起始地址。取元素时先从队列头开始,取完后,下一个元素就成了队列头,依次循环。只有一个元素时,既是队列头,也是队列尾。

六、环形队列图示

   

七、用数组模拟环形队列思路

  

八、编写java代码实现环形队列

8.1 java代码如下:

  1 public class CircleArrayQueueDemo {
  2     //测试CircleArrayQueue
  3     public static void main(String[] args) {
  4         CircleArrayQueue arrayQueue = new CircleArrayQueue(4);
  5         char key = ' ';   //用于接收用户输入的命令
  6         Scanner scanner = new Scanner(System.in);
  7         boolean loop = true;
  8         //输入一个菜单
  9         while (loop) {
 10             System.out.println("===========CircleArrayQueue============");
 11             System.out.println("s --> show : 显示队列");
 12             System.out.println("e -->  exit : 退出系统");
 13             System.out.println("a -->   add : 添加数据到队列");
 14             System.out.println("g -->    get : 从队列中取出数据");
 15             System.out.println("h -->   head : 查看队列头数据");
 16             System.out.println("===========CircleArrayQueue============");
 17             key = scanner.next().charAt(0);              //接收用户输入命令
 18             switch (key) {
 19                 case 's':                            //显示队列
 20                     try {
 21                         arrayQueue.showQueue();
 22                     } catch (Exception e) {
 23                         e.printStackTrace();
 24                     }
 25                     break;
 26                 case 'e':                             //退出系统
 27                     scanner.close();
 28                     loop = false;
 29                     break;
 30                 case 'a':                              //向队列添加数据
 31                     try {
 32                         System.out.println("请输入要添加的数据");
 33                         int num = scanner.nextInt();
 34                         arrayQueue.addQueue(num);
 35                     } catch (Exception e) {
 36                         e.printStackTrace();
 37                     }
 38                     break;
 39                 case 'g':                               //获取队列中的数据
 40                     try {
 41                         int res = arrayQueue.getQueue();
 42                         System.out.printf("取出的数据是\t%d \n", res);
 43                     } catch (Exception e) {
 44                         e.printStackTrace();
 45                     }
 46                     break;
 47                 case 'h':                                 //查看队列的头数据
 48                     try {
 49                         int head = arrayQueue.headQueue();
 50                         System.out.printf("队列的头数据是\t%d\n",head);
 51                     } catch (Exception e) {
 52                         e.printStackTrace();
 53                     }
 54                     break;
 55                 default:
 56                     break;
 57             }
 58         }
 59         System.out.println("队列退出!");
 60     }
 61 }
 62 
 63 
 64 class CircleArrayQueue {
 65     private int maxSize;  //表示数组的最大容量
 66     private int front;        //front做调整,指向队列中的第一个元素,默认初始值为0
 67     private int rear;          //rear做调整,约定指向最后一个元素的后一个位置,默认初始值为0
 68     private int[] arr;        //该数组用于存放数据,模拟队列
 69 
 70     //创建队列的构造器
 71     public CircleArrayQueue(int maxSize) {
 72         this.maxSize = maxSize;
 73         arr = new int[this.maxSize];           //创建对应长度的队列
 74         //front & rear 默认给定的值为 0 ,所以可以省略赋值操作
 75     }
 76 
 77     //判断队列是否为满
 78     public boolean isFull() {
 79         return (rear + 1) % maxSize == front;
 80     }
 81 
 82     //判断队列是否为空
 83     public boolean isEmpty() {
 84         return front == rear;
 85     }
 86 
 87     //添加数据到队列
 88     public void addQueue(int num) {
 89         //判断队列是否为满
 90         if (isFull()) {
 91             System.out.println("队列已满不能添加有效数据!");
 92             return;
 93         }
 94         //rear初始值为0,直接指向的就是下一个位置。所以可以直接将数据加入
 95         arr[rear] = num;
 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         /*
109          *   1. 先将front 对应的数据取出给临时变量 value
110          *   2. 将 front 后移 (取模后++)
111          *   3. 将临时变量存放的数据返回
112          */
113         int value = arr[front];
114         front = (front + 1) % maxSize;
115         return value;
116     }
117 
118     //显示队列中的有效数据
119     public void showQueue() {
120         //判断队列是否为空
121         if (isEmpty()) {
122             throw new RuntimeException("队列为空,无法获取到有效数据! ");
123         }
124         //因为添加了环形操作,所以这里不能再fori循环遍历取值了
125         //思路: 从 front开始向后遍历多少个数据进行输出打印
126         for (int i = front; i < front + size(); i++) {
127             System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
128         }
129     }
130 
131     //获取队列中的有效数据个数  ==》 用于取代静态的arr.length
132     public int size() {
133         return (rear + maxSize - front) % maxSize;
134     }
135 
136     //显示队列的头元素(只是显示,不是取出)
137     public int headQueue() {
138         //判断队列是否为空
139         if (isEmpty()) {
140             throw new RuntimeException("队列为空,无法获取头元素!");
141         }
142         return arr[front];
143     }
144 }

 


原文链接:https://blog.csdn.net/a1786742005/article/details/103977726

 

posted on 2021-03-17 02:18  H__D  阅读(179)  评论(0编辑  收藏  举报