本篇文章主要是为了解决上一篇文章中,数组使用一次就不能继续使用的问题,由于上一篇文章中的数组没有达到复用的效果,因此本篇文章使用算法,将数组改造成一个环形队列,以此达到复用的效果。
首先进行数组模拟环形队列的思路分析:
(1)将front变量的含义做一个调整,front指向队列中的第一个元素,也就是说arr[front]就是队列的第一个元素,front的初始值为0。
(2)将rear变量的含义做一个调整,rear指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定,rear的初始值为0。
(3)当队列满时,条件是(rear+1)%maxSize ==front
(4)当队列为空时,条件是 rear == front
(5)这样分析后,队列中有效的数据个数为(rear+maxSize-front)%maxSize。假设front=0,rear=2 公式算完之后为2
(6)可以在原来的队列基础上修改得到一个环形队列
环形队列主要算法上的改动就是使用了取模 %来实现循环复用。
下面就是修改后的部分关键方法代码:
public CircleArray(int arrMaxSize){ maxSize = arrMaxSize; arr = new int[maxSize]; front = 0; rear = 0; }
首先构造器中,front和rear的初始值发生改变,从-1变为0
//判断队列是否满 public boolean isFull(){ return (rear+1)% maxSize == front; }
判断队列是否满的条件发生改变
//添加数据到队列 public void addQueue(int n){ if(isFull()){ System.out.println("队列满,不能加入数据"); return; } //直接将数据加入 arr[rear] = n; //将rear后移,考虑取模 rear = (rear+1) % maxSize; //直接加1会导致数组越界 }
addQueue方法发生改变,直接将数据加入后需要取模,而不是+1,一直+1会导致数组越界。
//获取队列的数据,出队列 public int getQueue(){ if(isEmpty()){ System.out.println("队列空,不能取出数据"); //通过抛出异常 throw new RuntimeException("队列空,不能取出数据"); } //这里需要分析出front是指向队列的第一个元素 //1.先把front对应的值保存到一个临时变量 //2.将front后移,考虑取模 //3.将临时保存的变量返回 int value = arr[front]; front = (front +1) % maxSize; return value; }
getQueue方法发生改变,需要先把front对应的值保存到一个临时变量,之后将front后移,考虑取模,最后将临时保存的变量返回。
//显示队列的所有数据 public void showQueue(){ if(isEmpty()){ System.out.println("队列为空,没有数据"); return; } //思路:从front开始遍历,遍历多少个元素 // for(int i=front;i
showQueue方法中,用到了思路中提到的,队列中有效数据的个数,因此写了一个size方法,代码如下:
//求出当前队列有效数据的个数 public int size(){ return (rear + maxSize - front) % maxSize; }
最后运行截图如下,主要区别就是,之前的数组队列,在队列已经满之后,进行取出数据的操作,然后不能再添加,而现在的环形队列,假设队列中为10,20,30,队列已满,之后取出队列头部数据10,现在队列为20,30,可以继续进行添加操作,例如添加数据40,这样队列为20,30,40。
程序正确按照上面例子中的算法运行,结果正确。
最后附上数组模拟环形队列的全部代码:
/** To change this license header, choose License Headers in Project Properties.* To change this template file, choose Tools | Templates* and open the template in the editor.*/package queue;import java.util.Scanner;/**** @author Administrator*/public class CircleArrayQueueDemo {public static void main(String[] args){//测试数组模拟环形队列System.out.println("测试数组模拟环形队列");//这里设置的4,其队列的有效数据最大是3CircleArray queue = new CircleArray(4);char key = ' ';//接收用户输入Scanner input = 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(hrad):查看队列头的数据");key = input.next().charAt(0);switch(key){case 's':queue.showQueue();break;case 'a':System.out.println("输入一个数");int value = input.nextInt();queue.addQueue(value);break;case 'g':try{int res =queue.getQueue();System.out.println("取出的数据是"+ res);} catch(Exception e){System.out.println(e.getMessage());}break;case 'h': //查看队列头的数据try{int res =queue.headQueue();System.out.println("取出的队列头数据是"+ res);} catch(Exception e){System.out.println(e.getMessage());}break;case 'e':input.close();loop = false;break;default:break;}}System.out.println("程序退出");}}class CircleArray{private int maxSize; //表示数组的最大容量private int front ; //front指向队列头部元素,初始值为0private int rear; //rear指向队列的最后一个元素的后一个位置private int[] arr; //该数据用于存放数据,模拟队列public CircleArray(int arrMaxSize){maxSize = arrMaxSize;arr = new int[maxSize];front = 0;rear = 0;}//判断队列是否满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; //直接加1会导致数组越界}//获取队列的数据,出队列public int getQueue(){if(isEmpty()){System.out.println("队列空,不能取出数据");//通过抛出异常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.print(arr[i%maxSize]+"\t");}}//求出当前队列有效数据的个数public int size(){return (rear + maxSize - front) % maxSize;}//显示队列的头数据,注意不是取出数据public int headQueue(){if(isEmpty()){System.out.println("队列为空,没有数据");throw new RuntimeException("队列空,不能取出数据");}return arr[front ];}}