【数据结构与算法】顺序队列与环形队列

一 顺序队列

1 应用场景

银行排队、餐厅网上叫号系统使用的都是队列这种数据结构。

2 基本概念

(1)基本介绍

  • 队列是一个有序列表,可以用数组或是链表来实现,只允许在一端进行插入,在另一端删除。
  • 遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取出
  • 队列示意图如下:

在这里插入图片描述

(2)队列的顺序实现

使用数组模拟队列示意图:

在这里插入图片描述

(3)队列的入队和出队操作

队列本身是有序列表, 其中 maxSize 是该队列的最大容量。例如当队列最大长度MaxSize=5时:

在这里插入图片描述

约定rear总是指向队尾元素,front指向当前队中队头元素的前一位置 。

元素进队,rear增1,元素出队,front增1。

当rear=MaxSize-1时不能再进队。

(4)使用数组模拟队列

存入队列时称为”enQueue”,enQueue 的处理需要有两个步骤:

  • 将尾指针往后移:rear+1 , 当front == rear 【空】
  • 若尾指针 rear 小于队列的最大下标 maxSize-1,则将数据存入 rear所指的数组元素中,否则无法存入数据。 rear == maxSize - 1[队列满]

3 代码实现

(1)初始化队列

// 执行队列的初始化操作
public ArrayQuene(int maxSize) {
    
    
    this.maxSize = maxSize;
    rear = -1;      // 队尾元素
    front = -1;     // 队头元素
    arr = new int[maxSize];
}

(2)判断队列是否已满

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

(3)判断队列是否为空

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

(4)进队

// 将数据添加到队列
public void enQuene(int data){
    
    
    // 判断队列是否已满
    if(!isFull()){
    
    
        arr[++rear] = data;
        System.out.println("进队成功!");
    } else {
    
    
        System.out.println("队列已满,不能添加数据!");
    }
}

(5)出队

// 获取队列元素,出队
public void deQuene(){
    
    
    if(!isEmpty()){
    
    
        System.out.println(arr[++front]);
        System.out.println("元素:" + arr[front] + "出队成功!");
    }else{
    
    
        System.out.println("队列为空,出队失败!");
    }
}

(6)查看队列中元素

// 输出队列中的所有值
public void showQuene(){
    
    
    if(!isEmpty()){
    
    
        for(int i = 0; i < arr.length;i++){
    
    
            if(i > front && i <= rear){
    
    
                System.out.print(arr[i] + " ");
            }
    }
    }else{
    
    
        System.out.println("队列为空!");
    }
}

(7)获取队头元素

// 获取队头元素
public void getHead(){
    
    
    if(!isEmpty()){
    
    
        System.out.println("队头元素为:" + arr[front + 1 ] );
    }else{
    
    
        System.out.println("队列为空,无队头元素!");
    }
}

4 完整代码

public static void main(String[] args) {
    
    
    ArrayQuene arrayQuene = new ArrayQuene(5);
    String key = null;
    Scanner sc = new Scanner(System.in);
    boolean index = true;
    while(index){
    
    
        System.out.println("============================");
        System.out.println("show:显示队列");
        System.out.println("en  :进队");
        System.out.println("de  :出队");
        System.out.println("head:显示队头");
        System.out.println("exit:退出程序");
        System.out.println("============================");
        key = sc.nextLine();
        switch (key){
    
    
            case "show":
                arrayQuene.showQuene();
                break;
            case "en":
                System.out.println("请输入进队元素");
                int data = sc.nextInt();
                arrayQuene.enQuene(data);
                break;
            case "de":
                arrayQuene.deQuene();
                break;
            case "head":
                arrayQuene.getHead();
                break;
            case "exit":
                sc.close();
                index = false;
                break;
            default:
                break;
        }
    }
    System.out.println("程序已退出!");
}

public static class ArrayQuene{
    
    
    private int maxSize;
    private int front;
    private int rear;
    private int[] arr;      // 存储数据的值

    // 执行队列的初始化操作
    public ArrayQuene(int maxSize) {
    
    
        this.maxSize = maxSize;
        rear = -1;      // 队尾元素
        front = -1;     // 队头元素
        arr = new int[maxSize];
    }

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

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

    // 将数据添加到队列
    public void enQuene(int data){
    
    
        // 判断队列是否已满
        if(!isFull()){
    
    
            arr[++rear] = data;
            System.out.println("进队成功!");
        } else {
    
    
            System.out.println("队列已满,不能添加数据!");
        }
    }

    // 获取队列元素,出队
    public void deQuene(){
    
    
        if(!isEmpty()){
    
    
            System.out.println(arr[++front]);
            System.out.println("元素:" + arr[front] + "出队成功!");
        }else{
    
    
            System.out.println("队列为空,出队失败!");
        }
    }

    // 输出队列中的所有值
    public void showQuene(){
    
    
        if(!isEmpty()){
    
    
            for (int i : arr) {
    
    
                System.out.println(i + " ");
            }
        }else{
    
    
            System.out.println("队列为空!");
        }
    }

    // 获取队头元素
    public void getHead(){
    
    
        if(!isEmpty()){
    
    
            System.out.println("队头元素为:" + arr[front + 1 ] );
        }else{
    
    
            System.out.println("队列为空,无队头元素!");
        }
    }
}

二 环形队列

1 基本概念

使用顺序队列有一个问题:当队满之后,经过几次出队操作后,队列中虽然存在空位置,但是不能执行进队操作,具体情形如下图:

在这里插入图片描述

这是因为采用rear==MaxSize-1作为队满条件的缺陷。当队满条件为真时,队中可能还有若干空位置。

这种溢出并不是真正的溢出,称为假溢出。

解决方案就是把数组的前端和后端连接起来,形成一个环形的顺序表,即把存储队列元素的表从逻辑上看成一个环,称为环形队列或循环队列。

在这里插入图片描述

实际上内存地址一定是连续的,不可能是环形的,这里是通过逻辑方式实现环形队列,也就是将rear++和front++改为:

  • rear=(rear+1)%MaxSize
  • front=(front+1)%MaxSize

2 环形队列的几种状态

在这里插入图片描述

现在约定rear=front为队空,以下两种情况都满足该条件:
在这里插入图片描述

并约定(rear+1)%MaxSize=front为队满条件

当进队一个元素就到达队头时,就认为队满了。这样做会少放一个元素,牺牲一个元素没关系的

3 环形队列的四要素

队空条件:front = rear

队满条件:(rear+1)%MaxSize = front

进队e操作:rear=(rear+1)%MaxSize; 将e放在rear处

出队操作:front=(front+1)%MaxSize; 取出front处元素e;

在环形队列中,实现队列的基本运算算法与非环形队列类似,只是改为上述4要素即可。

4 代码实现

(1)初始化队列

// 初始化环形队列
public CircleArray(int maxSize){
    
    
    this.maxSize = maxSize;
    // 定义front执行环形队列的第一个元素,而非顺序队列中执行队头的前一个元素,rear同理
    front = 0;
    rear = 0;
    arr = new int[maxSize];
}

(2)判断队列是否已满

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

(3)判断队列是否为空

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

(4)进队

// 进队
public void enQuene(int data){
    
    
    if(!isFull()){
    
    
        // 注意与顺序队列的区别
        arr[rear++] = data;
        rear = rear % maxSize;
        System.out.println("元素:" + data + "进队成功!");
    }else {
    
    
        System.out.println("队列已满,进队失败!");
    }
}

(5)出队

// 出队
public void deQuene(){
    
    
    if(!isEmpty()){
    
    
        System.out.println("元素:" + arr[front++] + "出队成功!");
        front = front % maxSize;
    }else{
    
    
        System.out.println("队列为空,出队失败!");
    }
}

(6)查看队列中的元素

// 输出队列中的元素
public void showQuene(){
    
    
    if(!isEmpty()){
    
    
        // front从零开始
        for(int i = front; i < front + size(); i++) {
    
    
            // 当i大于rear时,说明队列已满且经过出队操作
            // 针对这种情况,输出rear后所有元素
            if ( (i >= front && i < rear) || (i > rear) ) {
    
    
                System.out.print(arr[i % maxSize] + " ");
            }
        }
    }else{
    
    
        System.out.println("队列为空!");
    }
}

(7)求队列中元素个数

// 求出数据中的元素个数,从1开始
public int size(){
    
    
    return (rear + maxSize - front) % maxSize;
}

(8)获得头元素

// 获取头元素
public void getHead(){
    
    
    System.out.println("队头元素为:" + arr[front % maxSize]);
}

5 完整代码

package com.hzy.datastructs;

import java.util.Scanner;

public class CircleArrayDemo {
    
    
    public static void main(String[] args) {
    
    
        CircleArray circleArray = new CircleArray(5);
        String key = null;
        Scanner sc = new Scanner(System.in);
        boolean index = true;
        while(index){
    
    
            System.out.println("============================");
            System.out.println("show:显示队列");
            System.out.println("en  :进队");
            System.out.println("de  :出队");
            System.out.println("head:显示队头");
            System.out.println("exit:退出程序");
            System.out.println("============================");
            key = sc.nextLine();
            switch (key){
    
    
                case "show":
                    circleArray.showQuene();
                    break;
                case "en":
                    System.out.println("请输入进队元素");
                    int data = sc.nextInt();
                    circleArray.enQuene(data);
                    break;
                case "de":
                    circleArray.deQuene();
                    break;
                case "head":
                    circleArray.getHead();
                    break;
                case "size":
                    circleArray.size();
                    break;
                case "exit":
                    sc.close();
                    index = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序已退出!");
    }

    public static class CircleArray{
    
    
        private int[] arr;
        private int front;
        private int rear;
        private int maxSize;

        // 初始化环形队列
        public CircleArray(int maxSize){
    
    
            this.maxSize = maxSize;
            // 定义front执行环形队列的第一个元素,而非顺序队列中执行队头的前一个元素,rear同理
            front = 0;
            rear = 0;
            arr = new int[maxSize];
        }

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

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

        // 进队
        public void enQuene(int data){
    
    
            if(!isFull()){
    
    
                // 注意与顺序队列的区别
                arr[rear++] = data;
                rear = rear % maxSize;
                System.out.println("元素:" + data + "进队成功!");
            }else {
    
    
                System.out.println("队列已满,进队失败!");
            }
        }

        // 出队
        public void deQuene(){
    
    
            if(!isEmpty()){
    
    
                System.out.println("元素:" + arr[front++] + "出队成功!");
                front = front % maxSize;
            }else{
    
    
                System.out.println("队列为空,出队失败!");
            }
        }

        // 输出队列中的元素
        public void showQuene(){
    
    
            if(!isEmpty()){
    
    
                // front从零开始
                for(int i = front; i < front + size(); i++) {
    
    
                    // 当i大于rear时,说明队列已满且经过出队操作
                    // 针对这种情况,输出rear后所有元素
                    if ( (i >= front && i < rear) || (i > rear) ) {
    
    
                        System.out.print(arr[i % maxSize] + " ");
                    }
                }
            }else{
    
    
                System.out.println("队列为空!");
            }
        }

        // 求出数据中的元素个数,从1开始
        public int size(){
    
    
            return (rear + maxSize - front) % maxSize;
        }

        // 获取头元素
        public void getHead(){
    
    
            System.out.println("队头元素为:" + arr[front % maxSize]);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_43923463/article/details/128500596
今日推荐