您的位置:首页 > 编程语言

图解&代码实现:数组模拟实现环形队列

2020-01-13 18:20 666 查看

数组模拟实现环形队列

实现:让数组达到复用的效果,即:当我们从数组队列中取出了数据,那取出数据后后这个空间可以再次使用

数组秒实现环形队列的思路分析

rear
指针指向
maxsize - 1
时,也就是当
rear = maxsize - 1
时,需要判断
rear
的前面是否有空闲空间,也就是说front是否产生了变化并且已经不在初始的那个位置了

思路如下:

  1. front的含义做调整 :front由原来的指向队列头的前一个位置调整为现在的front指向了队列头

    队列头:就是队列中第一个数据所在的位置

    即:

    queueArr[front]
    就是获取的队列中的第一个数据

说明:

  1. 原来front的初始值为 - 1 现在 front 的初始值为0

  2. 原来的front是不包含队列头的,现在的front是包含队列头的

  3. rear的含义做调整:rear从原来指向队列的最后一个数据调整为了现在的rear指向队列的最后一个数据的前一个位置

    调整rear的目的:预留一个空间作为约定

说明:

  1. 原来的rear的初始值为 - 1,现在的rear的初始值为0

  2. 原来的rear包含队列的最后一个数据,现在的rear是不包含队列的最后一个数据。

  3. 预留的空间是动态变化的,预留空间始终都在rear指向的

    最后一个数据
    的后一个位置

  4. rear和front含义发生调整后,判断队列满的条件是

    ( rear + 1 )% maxsize = front

    为什么要取模? 答:因为rear可能是一直增长的,从而达到数组空间复用的效果

    原先队列满的条件是

    rear = maxsize - 1
    因为 原先没有考虑数组空间的复用


4. 判断队列为空的条件是rear = front

  1. 经过以上分析,当rear和front含义发生调整后,队列中有效数据的个数 是

    (rear + maxsize - front) % maxsize

    为什么要取模?答:因为是环形队列,rear有可能指到队列最前面。

    打个比方,当

    rear = 0,maxsize = 4 ,front = 0
    时,该队列中有多少个有效的数据?

    分析:(0 + 3 - 0)% 3 = 0,该队列中有效的数据个数为0个,因为rear = front ,则证明是空队列

  2. 使用代码来实现“数组模拟实现环形队列”

代码展示:

public class CirCleQueueArrayTest{
public static void main(String[] agrs){
// 实例化CirCleArrayQueue
CirCleQueueArray cirCleArrayQueue = new CirCleQueueArray(3);
char key = ' ';
boolean flag = true;
java.util.Scanner input = new java.util.Scanner(System.in);
while(flag){
System.out.println("s(showQueue()) : 显示队列中的所有数据");
System.out.println("g(getQueue()) : 把数据从队列中取出来");
System.out.println("a(addQueue(int num)) : 把数据添加到队列中");
System.out.println("h (headQueue()) : 查看队列中的第一个数据");
System.out.println("i(size()) : 显示队列中的有效数据的个数");
System.out.println("e(exit) : 退出程序");
System.out.print("请选择:");
key  = input.next().charAt(0);
switch(key){
case 's':
cirCleArrayQueue.showQueue();
break;
default:
break;
case 'e':
flag = false;
break;
case 'i':
try{
System.out.println("队列中有效数据的个数为 " + cirCleArrayQueue.size());
}catch(Exception e){
System.out.println(e.getMessage());
}
break;
case 'a':
System.out.print("请输入一个数:");
int num = input.nextInt();
cirCleArrayQueue.addQueue(num);
break;
case 'g':
try{
cirCleArrayQueue.getQueue();
}catch(Exception e){
System.out.println(e.getMessage());
}
break;
case 'h':
try{
System.out.println( "队列的第一个数据为 " + cirCleArrayQueue.headQueue());
}catch(Exception e){
System.out.println(e.getMessage());
}
break;
}
}
System.out.println("程序正常退出~~~");
}
}
class CirCleQueueArray{
// 编写属性(共4个)
// rear 调整后的含义为:指向队列中的最后一个数据的前一个位置 ,rear 的初始值为0
private int rear;
// front 调整后的含义为: 指向队列头(即:队列中的第一个数据),front的初始值为 0
private int front;
// queueArr : 队列数组,数组模拟实现环形队列
private int queueArr[];
// maxsize 表示队列的最大容量,队列中的数据是存放在数组中的
private int maxsize;

// 编写无参构造
public CirCleQueueArray(){

}

// 编写带参构造,实现将局部变量maxsize的值赋值给成员变量maxsize 并对queueArr[]进行初始化
public CirCleQueueArray(int maxsize){
// 将局部变量maxsize的值赋值给成员变量maxsize
this.maxsize = maxsize;
// 对queueArr[]进行初始化
queueArr = new int[maxsize];
}

// 编写成员方法,判断队列是否为空isEmpty()
public boolean isEmpty(){
return rear == front;
}

// 编写成员方法,判断队列是否已满isFull()
public boolean isFull(){
return (rear + 1) % maxsize == front;
}

// 编写成员方法 ,求出队列中有效数据的个数
public int size(){
if(isEmpty()){
throw new RuntimeException("数组为空,没有有效数据");
}
return (rear + maxsize - front) % maxsize;
}

// 编写成员方法,实现入队列addQueue(int num),无返回值类型带参
public void addQueue(int num){
if(isFull()){
System.out.println("队列已满,不能实现入队列");
return;
}
// 直接将数据加入
queueArr[rear] = num;
// 将rear 指针后移,必须考虑到取模
rear = (rear + 1) % maxsize;
}
// 编写成员方法,实现出队列getQueue(),有返回值无参
public int getQueue(){
if(isEmpty()){
throw new RuntimeException("空队列,不能实现出队列");
}
// 第一步 先把queueArr[front]对应的保存在一个临时变量中
// 为什么要将queueArr[front]对应的保存在一个临时变量中? 因为 若直接返回的话,就没有往后移的机会了
int tempValue = queueArr[front];
// 第二步 将front后移,考虑取模
front = (front + 1) % maxsize;
// 将临时变量中的值返回
return tempValue;
}

// 编写成员方法,通过for循环 | 增强for循环遍历队列中的所有的数据
public void showQueue(){
if(isEmpty()){
System.out.println("队列为空,不能遍历队列");
return ;
}
for(int i  = front;i < front + size();i ++){
System.out.println("queueArr["+ i % maxsize +"] = " + queueArr[i % maxsize]);
}
}

// 编写成员方法,显示队列头 (即:队列中的第一个数据)
public int headQueue(){
if(isEmpty()){
throw new RuntimeException("空队列,无法查看");
}
return queueArr[front];
}
}

总结:

  1. 环形队列判满条件:
    (rear +1) % maxsize == front
  2. 环形队列判空条件:
    rear == front
  3. 环形队列有效数据的个数
    (rear + maxsize - front) % maxsize
  4. 环形队列中rear的含义:指向队列中最后一个数据的前一个位置,因为要预留一个空间作为约定
  5. 环形队列中front的含义:指向队列头(即:队列中的第一个数据)
  • 点赞 1
  • 收藏
  • 分享
  • 文章举报
My-Sun-Shine 发布了27 篇原创文章 · 获赞 12 · 访问量 1504 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: