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

news2024/11/17 7:29:18

文章目录

  • 一 顺序队列
    • 1 应用场景
    • 2 基本概念
      • (1)基本介绍
      • (2)队列的顺序实现
      • (3)队列的入队和出队操作
      • (4)使用数组模拟队列
    • 3 代码实现
      • (1)初始化队列
      • (2)判断队列是否已满
      • (3)判断队列是否为空
      • (4)进队
      • (5)出队
      • (6)查看队列中元素
      • (7)获取队头元素
    • 4 完整代码
  • 二 环形队列
    • 1 基本概念
    • 2 环形队列的几种状态
    • 3 环形队列的四要素
    • 4 代码实现
      • (1)初始化队列
      • (2)判断队列是否已满
      • (3)判断队列是否为空
      • (4)进队
      • (5)出队
      • (6)查看队列中的元素
      • (7)求队列中元素个数
      • (8)获得头元素
    • 5 完整代码

一 顺序队列

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]);
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/130217.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

React Native windows环境搭建

1.首先准备下载必须的依赖&#xff1a;Node、JDK 、Android Studio、夜神模拟器 ①Node可以直接到 官网 下载&#xff0c;版本必须大于14&#xff0c;我这边用的是v16.15.1 ②Jave JDK&#xff0c;我直接在360软件管家安装的&#xff0c;搜的是JDK 11&#xff0c;React Nativ…

【算法】双指针、位运算、离散化、合并区间

文章目录1.双指针2.位运算3.离散化4.区间合并1.双指针 双指针的算法可以优化时间复杂度,双指针&#xff0c;指的是在遍历对象的过程中&#xff0c;不是普通的使用单个指针进行访问&#xff0c;而是使用两个相同方向&#xff08; 快慢指针 &#xff09;或者相反方向&#xff08…

SQL调优SQLSERVER 数据页

1. 什么是数据页 一般来说&#xff0c;对大块资源或者数据进行高效管理都会按照一定粒度来划分的&#xff0c;比如说 Windows 对内存的管理就是按照 内存页 (4k) 来进行划分&#xff0c;言外之意就是 SQLSERVER 对 mdf 的管理也是按照 数据页 &#xff08;8k) 来划分的&#x…

(小记)matlab散点图

Matlab散点图两种画法一、plot画散点图二、scatter画散点图三、matlab工具画散点图plot画我可以设置坐标轴之类的&#xff0c;方便论文使用&#xff1b;scatter没设置成功。一、plot画散点图 参考&#xff1a;matlab中二维散点图,MATLAB实例&#xff1a;二维散点图 自用代码 …

一站式迁移,人大金仓助力保险业务无感升级

2021年3月&#xff0c;国家发布《中华人民共和国国民经济和社会发展第十四个五年规划和2035年远景目标纲要》&#xff0c;纲要明确提出“稳妥发展金融科技&#xff0c;加快金融机构数字化转型”、“推进金融业信息化核心技术安全可控&#xff0c;维护金融基础设施安全”。2022年…

如果通过股价均线分析股票

目录如果通过股价均线分析股票获取数据为什么要计算均价计算均价分析结果如果通过股价均线分析股票 获取数据 股票数据获取渠道非常丰富&#xff0c;可以通过上一篇文章 各大股票开放接口介绍中接口获取数据&#xff0c;需要提供技术支持的可以私聊。 为什么要计算均价 股票…

MongoDB:基础概述

MongoDB 是一个开源的、跨平台的、面向文档的、基于分布式文件存储的数据库系统&#xff0c;MongoDB 是由 C 语言开发&#xff0c;旨在为 Web 应用提供可扩展的高性能数据存储解决方案。在高负载的情况下&#xff0c;通过添加更多的节点&#xff0c;可以保证服务器性能。 本篇内…

【技术分享】无纸化会议|智慧教室同屏走RTSP组播还是RTMP?

技术背景 我们在做内网多人同屏&#xff08;比如无纸化会议、智慧教室同屏&#xff09;技术方案的时候&#xff0c;遇到个问题&#xff1a;到底使用轻量级RTSP服务实现组播&#xff0c;还是基于RTMP的解决方案&#xff1f; 先说为什么大家喜欢组播吧&#xff1a; 组播技术方…

js实现复制粘贴剪切功能

文章目录js实现复制粘贴功能方式一&#xff1a;原生方式实现复制粘贴剪切&#xff08;不推荐&#xff09;方式二&#xff1a;浏览器自带clipboard API实现复制粘贴&#xff08;推荐&#xff09;简介特点clipboard对象及相关APIClipboard.readText()Clipboard.read()Clipboard.w…

二叉树之红黑树

红黑树的起源 二分查找具有Ologn的时间复杂度&#xff0c;使用二分查找的基础是数据有序。很明显数组可以完成这一条件&#xff0c;但是数组也有缺点&#xff0c;扩容&#xff0c;增加&#xff0c;删除非常不方便。而链表则没有这些缺点&#xff0c;但是链表却不满足随机存取&…

第二十七讲:神州路由器PPP CHAP认证的配置

实验拓扑图如下所示 操作步骤&#xff1a; 步骤1&#xff1a;连接网络拓扑图。 步骤2&#xff1a;RouterA基本配置。 Router>enable &#xff01;进入特权模式 Router#config &#xff01;进入全局配置模式 …

React jsx 简介与一些语法规则

什么是 Jsx 简单例子&#xff1a; //create virtual dom , single quotes is not needconst VDOM <h1> Hello, React </h1> //appy virtual dom to pageReactDOM.render(VDOM, document.getElementById("test")) //first parameter is virtual dom, …

2022,我们追逐群星,也在追逐AIGC的无尽可能

2022年&#xff0c;是中国人追逐群星的里程碑之年。今年10月31日&#xff0c;中国天宫空间站的第二个科学实验模块——梦天实验舱&#xff0c;搭载长征五号B遥四运载火箭发射升空。随着之后天实验舱成功与之前发射的天和核心舱完成精准对接&#xff0c;中国空间站历史性地完成了…

使用支付宝沙盒 nodejs

1、 进入官网 https://auth.alipay.com/login/index.html 登录 2、下载秘钥转换工具 https://render.alipay.com/p/f/fd-jwq8nu2a/pages/home/index.html 3、生成密钥 注意&#xff0c;此时得到的应用私钥的格式是不对的&#xff0c;应用格式转换转换格式 4、通过3中的应用公钥…

并发编程——2.Java 线程

目录2.Java 线程2.1.创建和运行线程2.1.1.方法一&#xff1a;直接使用 Thread 类2.1.2.方法二&#xff1a;使用 Runnable 接口配合 Thread2.1.3.方法三&#xff1a;使用 FutureTask 配合 Thread2.2.观察多个线程同时运行2.3.查看进程线程的方法2.4.原理之线程运行2.5.线程的常见…

React学习06-React Router 6

React Router 6 概述 React Router 以三个不同的包发布到 npm 上&#xff0c;它们分别为&#xff1a; react-router: 路由的核心库&#xff0c;提供了很多的&#xff1a;组件、钩子。react-router-dom: 包含react-router所有内容&#xff0c;并添加一些专门用于 DOM 的组件&…

Elasticsearch处理表关联关系的N种方式

Elasticsearch处理表关联关系是比较复杂的问题&#xff0c;处理不好会出现性能问题、数据一致性问题等&#xff1b; 今天我们特意分享一下几种方式&#xff0c;对象类型&#xff08;宽表&#xff09;、嵌套类型、父子关联关系、应用端关联&#xff0c;每种方式都有特定的业务需…

CycloneDDS(3)安全Security

本规范定义了符合DDS实现的安全模型和服务插件接口(SPI)架构。DDS安全模型通过DDS实现调用这些SPI来实现。 构成DDS安全模型的三个插件是: 1、身份验证服务插件 提供验证调用DDS操作的应用程序和/或用户身份的方法。包括在参与者之间执行相互身份验证和建立共享秘密的设施…

深度学习模型训练的tricks总结

学习率角度 学习率是一个非常非常重要的超参数&#xff0c;这个参数呢&#xff0c;面对不同规模、不同batch-size、不同优化方式、不同数据集&#xff0c;其最合适的值都是不确定的&#xff0c;我们无法光凭经验来准确地确定lr的值&#xff0c;我们唯一可以做的&#xff0c;就…

从零开始配置vim(30)——DAP的其他配置

很抱歉这么久才来更新这一系列&#xff0c;主要是来新公司还在试用期&#xff0c;我希望在试用期干出点事来&#xff0c;所以摸鱼的时间就少了。加上前面自己阳了休息了一段时间。在想起来更新就过去一个多月了。废话不多说了&#xff0c;让我们开始进入正题。 在前一章&#…