数组模拟队列与环形队列的实现与深度剖析

引言

在计算机科学中,队列(Queue)是一种常见的数据结构,遵循“先进先出”(FIFO)的原则。队列的应用场景非常广泛,例如任务调度、消息队列、缓冲区管理等。本文将深入探讨如何使用数组来模拟队列,并进一步实现环形队列。通过代码示例和详细解析,帮助读者理解队列的核心概念及其实现方式。

一、数组模拟队列的实现

1.1 队列的基本概念

队列是一种线性数据结构,支持两种基本操作:

  • 入队(Enqueue):将元素添加到队列的尾部。

  • 出队(Dequeue):从队列的头部移除元素。

队列的特点是先进先出,即最先入队的元素最先出队。

1.2 数组模拟队列的代码实现

我们首先来看如何使用数组来模拟一个简单的队列。以下是代码实现:

public class ArrayQueueDemo {
}

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

    // 创建队列的构造器
    public ArrayQueue(int arrMaxSize) {
        maxSize = arrMaxSize;
        arr = new int[maxSize];
        front = -1; // 指向队列头部,指向的是头部的前一个位置
        rear = -1; // 指向队列尾部,指向队列尾部的具体位置,就是队列最后的一个数据
    }

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

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

    // 添加数据到队列
    public void addQueue(int n) {
        // 先判断队列是否已满
        if (isFull()) {
            System.out.println("队列满,不能加入数据");
            return;
        }
        rear++; // 让队尾向后移动
        arr[rear] = n; // 赋值
    }

    // 获取队列的数据,出队列
    public int getQueue() {
        // 判断队列是否为空
        if (isEmpty()) {
            // 队列为空抛出异常
            throw new RuntimeException("队列空,不能取数据");
        }
        front++; // front后移
        return arr[front];
    }

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

    // 显示队列的头数据,注意不是取数据
    public int headQueue() {
        // 判断
        if (isEmpty()) {
            throw new RuntimeException("队列为空,没有数据");
        }
        return arr[front + 1];
    }
}

1.3 代码解析

  • front 和 rear:分别指向队列的头部和尾部。初始时,front 和 rear 都为 -1,表示队列为空。

  • isFull():判断队列是否已满,条件是 rear == maxSize - 1

  • isEmpty():判断队列是否为空,条件是 rear == front

  • addQueue(int n):将元素添加到队列尾部。如果队列已满,则提示无法添加。

  • getQueue():从队列头部移除元素并返回。如果队列为空,则抛出异常。

  • showQueue():显示队列中的所有元素。

  • headQueue():查看队列头部的元素,但不移除。

1.4 测试代码

public static void main(String[] args) {
    // 创建一个队列
    ArrayQueue arrayQueue = new ArrayQueue(3);
    char key = ' '; // 接收用户输入
    Scanner scanner = 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 = scanner.next().charAt(0); // 接收一个字符
        switch (key) {
            case 's':
                arrayQueue.showQueue();
                System.out.printf("\n");
                break;
            case 'a':
                System.out.println("输入一个数");
                int value = scanner.nextInt();
                arrayQueue.addQueue(value);
                break;
            case 'g':
                try {
                    int res = arrayQueue.getQueue();
                    System.out.printf("取出的数据是%d\n", res);
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }
                break;
            case 'h':
                try {
                    int res = arrayQueue.headQueue();
                    System.out.printf("队列头的数据是%d\n", res);
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }
                break;
            case 'e':
                scanner.close();
                loop = false;
                break;
            default:
                break;
        }
    }
}

1.5 测试结果

通过上述代码,我们可以实现一个简单的队列,并进行入队、出队、查看队列头等操作。测试结果表明,该队列能够正常工作。

二、环形队列的实现

2.1 环形队列的概念

在普通队列中,当队列满时,即使队列头部有空闲空间,也无法继续添加元素。为了解决这个问题,引入了环形队列(Circular Queue)。环形队列通过循环利用数组空间,使得队列在逻辑上形成一个环,从而更高效地利用存储空间。

2.2 环形队列的代码实现

以下是环形队列的代码实现:

public class CircleArrayQueueDemo {
}

class CircleArray {
    private int maxSize; // 表示数组的最大容量
    private int front; // 指向队列的第一个元素
    private int rear; // 指向队列的最后一个元素的后一个位置
    private int[] arr; // 该数据用于存放数据, 模拟队列

    public CircleArray(int arrMaxSize) {
        maxSize = arrMaxSize;
        arr = new int[maxSize];
    }

    // 判断队列是否满
    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;
    }

    // 获取队列的数据,出队列
    public int getQueue() {
        // 判断队列是否为空
        if (isEmpty()) {
            // 抛出异常
            throw new RuntimeException("队列为空,不能取数据");
        }
        int value = arr[front];
        // 和新增队列一样,同样需要取余
        front = (front + 1) % maxSize;
        return value;
    }

    // 显示队列所有数据的个数
    public int size() {
        return (rear + maxSize - front) % maxSize;
    }

    // 显示队列所有数据
    public void showQueue() {
        // 判断是否为空
        if (isEmpty()) {
            System.out.println("队列为空,没有数据");
            return;
        }
        for (int i = front; i < front + size(); i++) {
            System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
        }
    }

    // 显示队列的头数据,注意不是取数据
    public int headQueue() {
        // 判断队列是否为空
        if (isEmpty()) {
            throw new RuntimeException("队列空的,没有数据");
        }
        return arr[front];
    }
}

2.3 代码解析

  • front 和 rearfront 指向队列的第一个元素,rear 指向队列的最后一个元素的后一个位置。

  • isFull():判断队列是否已满,条件是 (rear + 1) % maxSize == front

  • isEmpty():判断队列是否为空,条件是 rear == front

  • addQueue(int n):将元素添加到队列尾部。如果队列已满,则提示无法添加。

  • getQueue():从队列头部移除元素并返回。如果队列为空,则抛出异常。

  • size():计算队列中元素的个数。

  • showQueue():显示队列中的所有元素。

  • headQueue():查看队列头部的元素,但不移除。

2.4 测试代码

public static void main(String[] args) {
    // 测试一把
    System.out.println("测试数组模拟环形队列的案例~~~");

    // 创建一个环形队列
    CircleArray queue = new CircleArray(4); // 说明设置4, 其队列的有效数据最大是3
    char key = ' '; // 接收用户输入
    Scanner scanner = 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 = scanner.next().charAt(0); // 接收一个字符
        switch (key) {
            case 's':
                queue.showQueue();
                break;
            case 'a':
                System.out.println("输出一个数");
                int value = scanner.nextInt();
                queue.addQueue(value);
                break;
            case 'g': // 取出数据
                try {
                    int res = queue.getQueue();
                    System.out.printf("取出的数据是%d\n", res);
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }
                break;
            case 'h': // 查看队列头的数据
                try {
                    int res = queue.headQueue();
                    System.out.printf("队列头的数据是%d\n", res);
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }
                break;
            case 'e': // 退出
                scanner.close();
                loop = false;
                break;
            default:
                break;
        }
    }
    System.out.println("程序退出~~");
}

2.5 测试结果

通过上述代码,我们可以实现一个环形队列,并进行入队、出队、查看队列头等操作。测试结果表明,该环形队列能够正常工作,并且能够循环利用数组空间。

三、总结

本文详细介绍了如何使用数组模拟队列和环形队列,并通过代码示例和测试展示了其实现过程。普通队列的实现相对简单,但在空间利用率上存在局限性而环形队列通过循环利用数组空间,解决了普通队列的空间浪费问题,适用于需要高效利用内存的场景。

在实际开发中,队列的应用非常广泛,例如任务调度、消息队列、缓冲区管理等。理解队列的基本原理及其实现方式,对于编写高效、可靠的程序具有重要意义。希望本文能够帮助读者深入理解队列的概念及其实现方式,并在实际项目中灵活运用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值