java数据结构学习--队列(数组实现)

使用Java实现队列(数组)

1、首先定义这个队列的数据结构 

class Queue {
    // 队列的容量
    private int size;
    // 头指针 指向队列的第一个元素,初始值为 0
    private int front;
    // 尾指针 指向队列的最后一个元素的后一个位置,初始值为 0
    private int rear;
    // 队列 存放数据,模拟队列
    private int[] arr;
}

说明:

  • size:这个队列的大小
  • front:头指针,这个指针永远指向队列的头元素,初始值为 0
  • rear:尾指针,这个指针指向队列的最后一个元素的后一个元素,初始值为 0 ,所以这个队列的可用大小 = size - 1
  • arr:表示这个队列

为了便于理解,分别画出了队列为空,有值,队列满的三种状态,如下图所示:

 如图所示,当队列为空时,rear和front都为零(左图),当队列中有元素时rear指向队列最后一个元素的后一个位置(中间图),右图表示队列已满。

2、 队列中几种特殊状态的判断

  • 为空:当 rear = front 时,队列为空
  • 为满:当 (rear + 1) % size = front 时,表示队列已满
  • 添加数据:当添加数据的时候,rear 指针应该后移一位,所以 rear = (rear + 1) % size
  • 取出数据:取出数据的时候,front 指针也应该后移一位,所以 front = (front + 1) % size
  • 队列中的元素个数:队列中的元素个数 = (rear + size - front) % size

3、重要方法说明

  • 添加数据方法
public void add(int data) {
     if (isFull()) {
         System.out.println("队列已满,不能添加数据~~");
         return;
     }
     arr[rear] = data;
     // 将指针后移
     rear = (rear + 1) % size;
}

首先判断队列是否为满( isFull() 方法在最后代码中会给出),然后向数组中添加值,最后把 rear 指针向后移动一位,因为考虑到环形队列的情况,在计算 rear 指针的时候一定要取模,不然会数组越界。为了便于理解,请看下图:

 作图表示一个队列,当再添加一个数据的时候,这时 rear 指针应该后移一位,但是如果 rear 直接加1,则会导致数组下标越界,所以,rear应该指向0,如右图所示。所以 rear = (rear + 1) % size

  • 取出数据
public int get() {
    if (isEmpty()) {
        throw new RuntimeException("队列为空,不能取出数据~~");
    }
    int data = arr[front];
    front = (front + 1) % size;
    return data;
}

 首先判断队列是否为空(isEmpty() 方法会再后面一并给出,然后取出一个数据,然后 front 指针应该后移指向下一个数据,最后返回数据。在指针后移的时候也应该考虑环形队列的问题,不然也会导致数组下标越界。为了便于理解,请看下图。

 如图所示,左图为原始队列,当取出一个数据的时候 front 移向下一个数据,这时,如果只是 front + 1的话,会导致数组下标越界异常,所以这时 front = (front + 1) % size

  • 返回队列中有效数据的个数
public int size() {
    return (rear + size - front) % size;
}

 队列中有效数据的计算公式:(rear + size - front) % size

  • 显示队列中的元素
public void show() {
    if (isEmpty()) {
        System.out.println("队列为空,没法显示数据~~");
        return;
    }

    // 遍历取出队列中的元素
    // 思路: 从 front 开始遍历,取出后面 (队列大小)个元素
    for (int i = front; i < front + size(); i++) {
        System.out.printf("arr[%d]=%d\n", i % size, arr[i % size]);
    }
}

遍历的思路就是:从头指针开始遍历,取出后面 (队列大小)个元素,在取出数组中元素的时候,记得取模,即arr[i % size]。不然会数组越界。

4、完整代码:

package com.gamazing.queue;

import java.util.Scanner;

public class ArrayQueue {
    public static void main(String[] args) {
        // 初始化一个队列,队列大小为4,可用大小为3
        Queue queue = new Queue(4);
        // 接收输入
        char c = ' ';
        Scanner scanner = new Scanner(System.in);
        boolean flag = true;
        while (flag) {
            /*Runtime.getRuntime().exit(1);*/
            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): 查看队列头的数据");
            c = scanner.next().charAt(0);// 接收一个字符
            switch (c) {
                case 's':
                    queue.show();
                    break;
                case 'a':
                    System.out.println("输出一个数");
                    int value = scanner.nextInt();
                    queue.add(value);
                    break;
                case 'g': // 取出数据
                    try {
                        int res = queue.get();
                        System.out.printf("取出的数据是%d\n", res);
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h': // 查看队列头的数据
                    try {
                        int res = queue.showHead();
                        System.out.printf("队列头的数据是%d\n", res);
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e': // 退出
                    scanner.close();
                    flag = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出~~");
    }

}

class Queue {

    // 队列的容量
    private int size;
    // 头指针 指向队列的第一个元素,初始值为 0
    private int front;
    // 尾指针 指向队列的最后一个元素的后一个位置,初始值为 0
    private int rear;
    // 队列 存放数据,模拟队列
    private int[] arr;

    // 构造方法
    public Queue(int arraySize) {
        this.size = arraySize;
        arr = new int[size];
        front = 0;
        rear = 0;
    }

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

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

    // 添加数据
    public void add(int data) {
        if (isFull()) {
            System.out.println("队列已满,不能添加数据~~");
            return;
        }
        arr[rear] = data;
        // 将指针后移
        rear = (rear + 1) % size;
    }

    // 取出数据
    public int get() {
        if (isEmpty()) {
            throw new RuntimeException("队列为空,不能取出数据~~");
        }
        int data = arr[front];
        front = (front + 1) % size;
        return data;
    }

    // 返回队列中有效数据的个数
    public int size() {
        return (rear + size - front) % size;
    }

    // 显示队列
    public void show() {
        if (isEmpty()) {
            System.out.println("队列为空,没法显示数据~~");
            return;
        }

        // 遍历取出队列中的元素
        // 思路: 从 front 开始遍历,取出后面 (队列大小)个元素
        for (int i = front; i < front + size(); i++) {
            System.out.printf("arr[%d]=%d\n", i % size, arr[i % size]);
        }
    }

    // 显示头元素
    public int showHead() {
        if (isEmpty()) {
            throw new RuntimeException("队列为空,不能取出数据~~");
        }
        return arr[front];
    }
}

第一次使用 Java 来实现队列,如果有问题,或者更好的办法,请大家及时指出。

猜你喜欢

转载自blog.csdn.net/G_amazing/article/details/95798789