队列、环形队列-Java数据结构和算法

Java队列的数组实现


前言

       生活中很多情况都是先来后到, 最直接的就是银行的业务了吧, 先来的先处理, 队列可以看成是顺序的结构, 我们排队来一个新人是排在这一队的尾部, 每次处理头部的一个人, 队列可以用数组 和链表来实现


一、队列介绍

      队列本身是有序的列表, 若使用数组的结构来存储队列的数据, 则队列数组中的声明如下面所示( 我们用maxSize来代表队列最大容量):
      因为队列的输入、输出分别从前后端来进行处理的。所以需要两个变量(相当于指针的作用)分别来记录队列的 队首 和 队尾 的下标。显然,front会随数据的输出发生变化(在头部出队列:排队的时候在前面的先走);rear是在数据输入的时候发生变化(新的人过来,排在队尾),具体如下图所示(将两个指针都初始化为-1):

在这里插入图片描述

二、数组模拟队列

1.编写 队列 的类

代码如下:

class ArrayQueue{
	private int maxSize;//队列容量
	private int front;  //队列头
	private int rear;	//队列尾
	private int[] arr;	//存放数据,模拟队列
//构造器:
	public ArrayQueue(int maxSize){
        this.maxSize = maxSize;
        arr = new int[maxSize];
        front = -1; //指向对象头部,指向队列头的前一个位置
        rear = -1;  //指向队列的尾部,指向队列尾部具体的数据(就是队列最后一个数据)
    }
}

2.判断队列是否满

当rear指针等于maxSize - 1的时候就满了,代码如下:

//判断队列是否满
public boolean isFull(){
	return rear == maxSize - 1;//上面已经提到
}

3.判断队列是否空

当rear指针等于front即为空(和排队时候对比即可),代码如下:

//判断队列是否为空
public boolean isEmpty(){
	return rear == front;
}

4.入队列

当我们将数据存入队列的时候,定义方法"addQueue()",处理分为两个步骤即可:
	1.调用isFull()方法判断队列是否满;
	2.若队列没有满,可以添加数据:
		2.1 尾指针rear后移:即rear = rear + 1;(指针指向空位置给新人)
	    2.2 将数据存入rear所指的数组位置中即可,
	  否则,不能加入数据(提醒用户),返回即可

代码如下:

//    添加数据
public void addData(int data){
    if(isFull()){
        System.out.println("队列满,加入数据失败...");
        return;
    }
    rear++;//排队有人过来了,队尾指针后移(到空位置)
    arr[rear] = data;//
}

5.出队列

当我们出队列的时候,处理分为以下两个步骤即可:
	1.调用isEmpty()方法判断队列是否空;
	2.若队列不为空,可以出队列(还有人在排队):
		2.2 将头指针front后移(指向的第一个顾客前一个位置),找到第一个顾客
		2.3 将arr[front]出列即可(对顾客进行服务)
	  否则,不能出队列(这里我们采用抛出异常的方法(也可打印提示))
	抛出自定义的运行时异常,不用再进行return;(基础知识点,需要注意下)

代码如下:

public int getData(){
   if(isEmpty()){
        throw new RuntimeException("队列为空,不能取数据");
    }
    front++;//front后移
    return arr[front];
}

6.遍历队列

当我们遍历队列的时候,分为以下步骤:
	1.调用isEmpty()方法判断队列是否空;
	2.若队列不为空,用 foreach 遍历即可:
	  否则,提示队列为空即可;

代码如下:

public void showData(){
    //遍历
    if(isEmpty()){
        System.out.println("队列为空,没有数据");
        return;
    }
    for(int i = 0 ; i < arr.length ; i++){
        System.out.printf("a[%d] = %d\n" , i , arr[i]);
    }
}

三、数组模拟环形队列

       对上面的数组进行优化,充分利用数组:将其看作一个环形的(我们在此通过取模的方式完成) :

1.调整思路如下:

1.front变量的含义做一个改变:front就是指向队列第一个元素。
	也就是说,现在arr[front]就是队列的第一个元素;front的初始值 = 02.rear变量的含义做出调整:rear就是指向的队列的元素的后一个位置。
	因为希望空出一个空间来做一个约定(可以不预留)。rear初始值 = 03.当队列满的时候,条件是(rear + 1% maxSize == front
4.队列为空的时候,rear == front
5.队列中有效的数据个数为:(rear + maxSize - front) % maxSize

2. CircleArray的实现:

class CircleArray{
    private int maxSize;    //表示数组最大容量
    private int front;      //队列首部
    private int rear;       //队列尾部
    private int[] arr;      //该数组用于存放数据,模拟队列

    //    创建队列的构造器
    public CircleArray (int maxSize){
        this.maxSize = maxSize;
        arr = new int[maxSize];
        front = 0;//初始化为0
        rear = 0;//初始化为0
    }
}

3.添加数据(入队列)

public void addData(int data){
    if(isFull()){
        System.out.println("队列满,不能加入数据");
        return;
    }
    arr[rear] = data;
    //后移数据
    rear = (rear + 1) % maxSize;
}

4.获取数据(出队列)

public int getData(){
    if(isEmpty()){
        throw new RuntimeException("队列为空,不能取数据");
    }
    //这里考虑front指向的队列第一个元素
    //1.先把front对应的值保存到一个临时变量
    //2.将front后移,考虑取模
    //3.将临时变量的值返回
    int value = arr[front];
    front = (front + 1) % maxSize;
    return value;
}

5.得到有效数据个数🔺

public int size(){
    return (rear + maxSize - front) % maxSize;
}

6.队列是否为空

public boolean isEmpty(){
    return rear == front;
}

7.队列是否满

//    判断队列是否满
public boolean isFull(){
    return ((rear + 1) % maxSize == front);
}

8.遍历环形队列

//    显示队列的所有数据
public void showData(){
    //遍历
    if(isEmpty()){
        System.out.println("队列为空,没有数据");
        return;
    }
    for(int i = front ; i < front + size() ; i++){
    //这里需要注意一下:
        System.out.printf("a[%d] = %d\n" , i % maxSize , arr[i % maxSize]);
    }
}

四、总结

1. 对于普通的队列:front指向的是第一个元素的前一个位置;
2. 对于普通的队列:rear指向的是最后一个数据本身位置;
3. 对于环形队列:reae指向最后一个数据的后一个位置;
4. 对于环形队列:front指向的就是第一个数据的位置;
5. 对于环形队列(front 和 rear初始为0):
       需要注意的是关于队列中元素个数的计算方式;

测试代码

public class ArrayQueueDemo {
    public static void main(String[] args) {
        //测试
        ArrayQueue queue = new ArrayQueue(3);
        char key = ' ';//接收用户输入;
        Scanner s = 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(head):查看队列头部数据");
            key = s.next().charAt(0);
            switch (key){
                case 's':
                    queue.showData();
                    break;
                case 'a':
                    System.out.println("请输入添加的数字:");
                    int data = s.nextInt();
                    queue.addData(data);
                    break;
                case 'g':
                    try {
                        int res = queue.getData();
                        System.out.println("去除的数据是:" + res);
                    }catch(Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h':
                    try {
                        int head = queue.headData();
                        System.out.println("队列头的数据是" + head);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                default:
                    System.out.println("操作不存在,请重新输入:");
                    break;
            }
        }
    }
}


class ArrayQueue{
    private int maxSize;    //表示数组最大容量
    private int front;      //队列首部
    private int rear;       //队列尾部
    private int[] arr;      //该数组用于存放数据,模拟队列

//    创建队列的构造器
    public ArrayQueue(int maxSize){
        this.maxSize = maxSize;
        arr = new int[maxSize];
        front = -1; //指向对象头部,指向队列头的前一个位置
        rear = -1;  //指向队列的尾部,指向队列尾部具体的数据(就是队列最后一个数据)
    }
//    判断队列是否满
    public boolean isFull(){
        return rear == maxSize - 1;
    }
//    判断队列是否为空
    public boolean isEmpty(){
        return rear == front;
    }
//    添加数据
    public void addData(int data){
        if(isFull()){
            System.out.println("队列满,不能加入数据");
        }
        rear++;
        arr[rear] = data;
    }
//    获取数据
    public int getData(){
//        判断是否为空
        if(isEmpty()){
            throw new RuntimeException("队列为空,不能取数据");
        }
        front++;
        return arr[front];
    }
//    显示队列的所有数据
    public void showData(){
        //遍历
        if(isEmpty()){
            System.out.println("队列为空,没有数据");
            return;
        }
        for(int i = 0 ; i < arr.length ; i++){
            System.out.printf("a[%d] = %d\n" , i , arr[i]);
        }
    }
//    显示头部数据
    public int headData(){
//        判断
        if(isEmpty()){
            throw new RuntimeException("队列为空,没有数据...");
        }
        return arr[front + 1];
    }

}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值