队列

53 阅读3分钟

基本介绍

  • 队列是一个有序列表,可以用数组或者链表来实现;
  • 队列遵循先入先出的原则,即:先存入队列的数据要先取出,后存入的数据要后取出来。

实现方式

数组模拟队列

队列本身是有序列表,使用数组的结构来存储队列的数据。

实现思路

  • maxSize 是该队列的最大容量;
  • 因为队列的输出、输入是分别从前后端来处理,因此需要两个变量 front 及 rear 分别记录队列前后端的下标,front 会随着数据输出而改变,而 rear 则是随着数据输入而改变,如图所示:

image.png

实现逻辑

入队列操作 addQueue

  1. 将尾指针往后移:rear+1 , 当 front == rear 时标识队列空;
  2. 若尾指针 rear 小于队列的最大下标 maxSize-1,则将数据存入 rear 所指的数组元素中,当 rear == maxSize - 1 时标识队列满。
public boolean addQueue(int temp) throws Exception {
    if (isFull()) {
        throw new Exception("队列已满,不能添加元素");
    }
    this.rear++;
    nums[rear] = temp;
    return true;
}

出队列操作 pop

  1. 当 front == rear 时标识队列空,队列里没有元素;
  2. 将头指针往后移:front+1 ,获取头元素。
public int pop() throws Exception {
    if (isEmpty()) {
        throw new Exception("队列已空,不能获取元素");
    }
    this.front++;
    int result = nums[front];
    nums[front] = 0;
    return result;
}

显示队列的情况 showQueue

public void show() {
    for (int temp : nums) {
        System.out.print(temp + " ");
    }
    System.out.println();
}

查看队列头元素 headQueue

  1. 当 front == rear 时标识队列空,队列里没有元素;
  2. 将下标定位到头指针后一位,但不移动头指针,获取头元素。
public int get() throws Exception {
    if (isEmpty()) {
        throw new Exception("队列已空,不能获取元素");
    }
    return this.nums[this.front + 1];
}

问题分析并优化

  1. 队列用完即弃,无法复用,可以改造成循环队列,达到循环利用的效果;
  2. 队列一经创建无法扩容,可以添加队列满则自动扩容函数。

数组模拟环形队列

通过将数组取模的方式来实现一个环形队列。

实现思路

  1. front 指向队列的第一个元素,也就是说 arr[front] 就是队列的第一个元素,front 的初始值为0;
  2. rear 指向队列的最后一个元素的后一个位置,因为希望空出一个空间做为约定,rear 的初始值为0;
  3. 当队列满时,条件是 (rear + 1) % maxSize == front;
  4. 对队列为空的条件 rear == front;
  5. 队列中有效的数据的个数 (rear + maxSize - front) % maxSize;  // 比如 rear = 1、front = 0。

image.png

实现逻辑

入队列操作 addQueue

  1. 此时 rear 指向队列尾节点,可以直接设置;
  2. 防止尾指针超过数组界限,需要对 rear + 1 后对 maxSize 取模。
public void add(int temp) throws Exception {
    if (isFull()) {
        throw new Exception("队列已满,不能添加元素");
    }
    nums[rear] = temp;
    rear = (rear + 1) % maxSize;
}

出队列操作 getQueue

  1. 此时 front 指向队列头节点,可以直接获取;
  2. 需要将 front 指向下一个节点,同样为了避免数组越界,对 front + 1 后对 maxSize 取模。
public int pop() throws Exception {
    if (isEmpty()) {
        throw new Exception("队列已空,不能获取元素");
    }
    int temp = nums[front];
    front = (front + 1) % maxSize;
    return temp;
}

显示队列的情况 showQueue

public void show() {
    for (int i = front; i < front + size(); i++) {
        System.out.printf("arr[%d]=%d\n", i % maxSize, nums[i % maxSize]);
    }
}

获取队列有效长度 size

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

查看队列头元素 headQueue

  • 此时front指向队列头节点,可以直接获取。
public int get() throws Exception {
    if (isEmpty()) {
        throw new Exception("队列已空,不能获取元素");
    }
    return nums[front];
}

应用场景