数据结构与算法基础(王卓)(12):队列的定义及其基础操作(解决假上溢的方法,循环队列解决队满时判断方法,链队和循环队列的初始化等)

news2024/12/27 1:54:22

循环队列:


解决假上溢的方法:引入循环队列(判断是否溢出)

将入队操作由:

base[rear]=x;

rear++;

准确的来说,是:

    Q.base[Q.rear]=x; 
    Q.rear++;

改为

Q.base[Q.rear]=x;

Q.rear=(Q.rear+1)% MAXQSIZE;


将出队操作由:

x=base[front];

front++;

改为

x=Q.base[s.front]

Q.front=(Q.front+1)%MAXQSIZE


准确(总的)来说:

就是将两指针自增的操作改(改进优化)为自增并取余的操作

这样,我们就实现了让队列形成一个循环顺序的结构:

后面新加进来的元素全部都可以重新从队列的数组(的)头部重新实现排序(按顺序)插入


Q:

如何判断和重新插入的时候数组里面已经清空了元素???

A:

首先,根据队列的结构特性,其数据存储形式必定是属于连续存储的形式

所以队头和队尾之外的数组空间内必定是没有我们所需要的、有用的数据在数组当中的

综上所述,在我们不断进行新插入元素的情况之下

除非出现两指针(位序)相等,即真(的)队满溢出的情况

新插入元素存储的位置里面一定是没有(有用的)数据元素的




循环队列解决队满时判断方法:少用一个元素空间

原本:

队空:front==rear

队满:front==rear

此时 无法区分:队空和队满 两种情况

注:

这里我们特别需要注意,队尾指针(rear)指向的位置

并不是队列最后插入的元素(队尾)的位置,而是队列最后插入的元素(队尾)的后一位的位置


如何实现少用一个元素空间:(实现区分判断队空和队满)

(rear+1) % MAXQSIZE = front;

当该语句为真,即:

当队尾指针(队列最后插入的元素(队尾)的后一位的位置)再往下面前进一格即为队头指针

也就是说,此时队列当中必定还有一个空着的位置(空间)

rear队尾指针就指向这一空间

如果我们在此时(这种情况下)判定这种队列中空着一个元素空间的情况为队满的情况

那我们就实现了:区分开队空和队满判断语句 的功能

解决了上面无法区分开队空和队满判断语句的问题,即:

(rear+1) % MAXQSIZE = front;

为真,判定为队满


前置条件:

//线性表的定义及其基础操作
#include<iostream>
using namespace std;
#include<stdlib.h>//存放exit
#include<math.h>//OVERFLOW,exit

#define TRUE        1
#define FALSE       0
#define OK          1
#define ERROR       0
#define INFEASIBLE  -1
#define OVERFLOW   -2   

#define MAXlength 100  //初始大小为100,可按需修改
typedef int Status;         //函数调用状态

struct Poly
{
    float p;
    int e;

    bool operator==(Poly t)
    {
        return t.p == p && t.e == e;
    }
    bool operator!=(Poly t)
    {
        return t.p != p || t.e != e;
    }
};

struct Sqlist
{
    Poly* elem;
    int length;
};

typedef Poly QElemType;

struct SqQueue
{
    QElemType* base;//初始化的动态分配存储空间
    int rear;//头指针
    int front;//尾指针
};

rear:后面的


 操作汇总:

初始化

求长度

取队头元素

入队和出队

PPT上没写(实用性不大)的操作:

销毁与清空


初始化:

project 1:

Status InitQueue(SqQueue &Q)//初始化
{
    Q.base = new QElemType[MAXQSIZE];
    Q.rear = Q.front = 0;
    return true;
}

但是这里我们忘了存储分配失败的情况:

    if (!Q.base) exit(OVERFLOW);//存储分配失败

 project 2:

Status InitQueue(SqQueue &Q)//初始化
{
    Q.base = new QElemType[MAXQSIZE];
    //Q.base = (QElemType*)malloc(MAXQSIZE * sizeof(QElemType));
    if (!Q.base) exit(OVERFLOW);//存储分配失败
    Q.rear = Q.front = 0;
    return true;
}

注意:同样的,这里开辟空间不能写成如下形式:

    QElemType Q.base = new QElemType[MAXQSIZE];

详情详见:

数据结构与算法基础(王卓)(8)附:关于new的使用方法详解_宇 -Yu的博客-CSDN博客_数据结构new


求长度:

Status Queuelength(SqQueue Q)//求长度
{
    return(Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}

为什么必须要加一轮进制数,原因出在C++取余算法的运行机制当中:

在编译器中,两个异号的数取余之后的结果取决于分子(被除数)的符号

负数%负数,编译器会将分母的负数自动转换为正整数,

然后再将分子负数的负号提取出来,将两个正整数取余,最后的结果加上负号

负数%正数,编译器先将分子负数的负号提取出来,将两个正整数取余,最后结果加上负号

正数%负数:

编译器自动将分母负数转换为正整数,然后两个正整数取余得到就是最终结果

比如说:

理论上我们知道两指针在该情况下和+2一样,都只差两个身位(位置),但是实际情况就是:

- 4 mod 6 = - 4;

2 mod 6 = 2 ;

所以在此,我们必须在被除数的基础之上再加一层进制数,来确保我们求数据长度函数的运算没有问题


取队头元素:

QElemType GetHead(SqQueue Q)//取队头元素
{
    if (Q.front != Q.rear)
        //别忘排除空表的情况
        return(Q.base[Q.front]);
}

别忘排除空表的情况!


入队和出队:

Status EnQueue(SqQueue& Q, QElemType e)//入队
{
    if ((Q.rear + 1) % MAXQSIZE == Q.front)
        return OVERFLOW;
    Q.base[Q.rear] = e;
        //这里rear只是下标,不是指针,所以只能这样用
    Q.rear = (Q.rear + 1) % MAXQSIZE;
    return true;
}

Status DeQueue(SqQueue& Q, QElemType e)//出队
{
    if (Q.front == Q.rear)
        return NULL;
    e = Q.base[Q.front];
    Q.front = (Q.front + 1) % MAXQSIZE;
    return true;
}

链式队列:

初始化,销毁,入队,出队,求顶部元素



前置条件:

//链表的定义及其基础操作
#include<iostream>
using namespace std;
#include<stdlib.h>//存放exit

#define TRUE        1
#define FALSE       0
#define OK          1
#define ERROR       0
#define INFEASIBLE  -1
#define OVERFLOW   -2   


typedef int Status;         //函数调用状态

struct K
{
    float a;
    int b;
    string c;
    bool operator==(K& t)
    {
        return t.a == a && t.b == b;
        //&& t.c = c;
    }
    bool operator!=(K& t)
    {
        return t.a != a || t.b != b;
        //|| t.c = c;
    }
};
typedef K Elemtype;         //函数调用状态

struct Lnode
    //node:结; 结点;
{
    Elemtype data;
    Lnode* next;
};
typedef Lnode* LinkList;

typedef K QElemType;
typedef int Status;         //函数调用状态
#define MAXQSIZE 100  //初始大小为100,可按需修改

struct QNode//一个链队结点的结构
{
    QElemType data;
    QNode* next;
};
typedef QNode* QuenePtr;//Pointer

struct LinkQueue
{
    QuenePtr front; // 队头指针
    QuenePtr rear; // 队尾指针
};

int main()
{

}

初始化

Status InitQueue(LinkQueue& Q)//初始化
{
    Q.front = Q.rear = new QNode;
    if (!Q.front)
        return false;
    Q.rear->next = NULL;
    return true;
}

销毁

project 1:

Status DesQueue(LinkQueue& Q)//销毁
{
    while (Q.rear)
    {
        auto p = Q.rear->next;
        delete  Q.rear;
        Q.rear = p;
    }
    return true;
}

注意,我们从头往后一个一个销毁,用的是front指针而不是rear指针

最终成品:

Status DesQueue(LinkQueue& Q)//销毁
{
    while (Q.front)
    {
        QNode* p = Q.front->next;
        delete (Q.front); 
        Q.front = p;
    }
    //也可以直接指定指针rear暂时储存Q.front->next的地址,反正他放在这闲着也没事
    //Q.rear=Q.front->next; free(Q.front); Q.front=Q.rear;
    return OK;
}

注意,这里因为我们前面开辟空间时用的是new,所以这里写的是delete

如果根据PPT上面的malloc开辟空间,释放空间的语句就应该用free,详见:

free 与 delete 区别_free delete_460833359的博客-CSDN博客


入队:

Status EnQueue(LinkQueue& Q, QElemType e)//入队
{
    QNode* p = new QNode;
    //QNode* p = (QuenePtr)malloc(sizeof(QNode));
    p->data = e;
    p->next = NULL;
    Q.rear->next = p;
    Q.rear = p;
    return OK;
}

注意:从这里我们就能知道:

链队的头指针指向的是一个空着的结点


出队:

project 1:

Status DeQueue(LinkQueue& Q, QElemType e)//出队
{
    QNode* p = Q.front->next;
    delete Q.front;
    Q.front = p;

    return true;
}

参考PPT完善程序:

注意:

链队的头指针指向的是一个空着的结点

(1):链队指向的第一个节点是一个头结点,不是队列的第一个元素

所以其实整个程序需要全部重新翻新修改

(2):根据新顺序,让头指针找到出队后的队列的队头

Q.front->next = p->next;

(3):出队之前,需先判断队列是否为空

if (Q.front == Q.rear) return ERROR;

project 2:

Status DeQueue(LinkQueue& Q, QElemType e)//出队
{
    QNode* p = Q.front->next;
    e = p->data;//保存删除的信息
    Q.front->next = p->next;

    delete p;

    return true;
}

(4):如果删除到最后队列当中就只有一个元素节点了

那么这时尾指针的位置也需要做出调整改变:

if (Q.rear == p) Q.rear = Qfront;

如果不作出调整(即不写这个(句)语句),就会导致删除结点以后我们对队尾指针也没了

队列中只剩下front指针

最终成品:

Status DeQueue(LinkQueue& Q, QElemType e)//出队
{
    if (Q.front == Q.rear) return ERROR;
    QNode* p = Q.front->next;
    e = p->data;//保存删除的信息
    Q.front->next = p->next;
    if (Q.rear == p)
        Q.rear = Q.front;
    delete p;
    return true;
}

求链队列的队头元素:

Status GetHead(LinkQueue Q, QElemType& e)
{
    if (Q.front == Q.rear) return ERROR;
    e = Q.front->next->data;
    return OK;
}

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

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

相关文章

摘录一下Python列表和元组的学习笔记

1 基础概念 列表一个值&#xff0c;列表值指的是列表本身&#xff0c;而不是列表中的内容 列表用[]表示 列表中的内容称为 表项 len()函数可以显示列表中表项的个数&#xff0c;比如下面这个例子 spam [cat, bat, dog, rat]print(len(spam))列表的范围选取中&#xff0c;比…

96.【SpringBoot接入支付宝-thymeleaf-springBoot】

SpringBoot接入支付宝(一)、前提工作:1、进入支付宝开发平台—沙箱环境1.1、进入个人沙箱环境1.2、接下来进行几个密钥的生成1.3、拿到两个密钥后&#xff0c;进行自定义密钥配置1.4、至此&#xff0c;我们沙箱环境的配置和基本参数都已经获取到。(二)、Java代码-thymeleaf1.导…

蓝桥杯-超级质数

蓝桥杯-超级质数1、问题描述2、解题思路3、代码实现1、问题描述 如果一个质数 P 的每位数字都是质数, 而且每两个相邻的数字组成的两位 数是质数, 而且每三位相邻的数字组成的三位数是质数, 依次类推, 如果每相邻的 k 位数字组成的 k 位数都是质数, 则 P 称为超级质数。 如果把…

重型工业机械设备远程监控解决方案

随着企业的发展&#xff0c;各类机械设备日益增多&#xff0c;为了实现高效的管理和使用&#xff0c;保障安全生产&#xff0c;建立智能化、信息化的工业制造系统成为了必然趋势。 传统的机械设备管理大多采用人工方式&#xff0c;现场作业人员需要每天通过电话、或者E-mail等方…

利用反射实现通过读取配置文件对类进行实例化-课后程序(JAVA基础案例教程-黑马程序员编著-第十二章-课后作业)

【案例12-3】&#xff1a;利用反射实现通过读取配置文件对类进行实例化 【案例介绍】 1.案例描述 现在有一个项目&#xff0c;项目中创建了一个Person类&#xff0c;在Person类中定义了一个sleep()方法。在工程中还定义了一个Student类继承Person类&#xff0c;在Student类中…

项目管理PMP证书的含金量真的高吗?

含金量当然高的&#xff0c;特别是在项目管理这个领域&#xff0c;绝对是知名度最高的&#xff0c;行业内最受认可的相关证书&#xff0c;含金量等同于于MBA&#xff0c;那么&#xff0c;除去它本身专业知识价值&#xff0c;它的含金量高在哪里呢&#xff1f; &#xff08;含资…

linux离线状态下将视频mp4格式转换m3u8

因为业务需求&#xff0c;python文件生成的视频为MP4格式&#xff0c;无法在前端浏览器正常播放&#xff0c;需切换m3u8格式&#xff0c;但因为服务器是没有网络的&#xff0c;因袭需要在离线状态下进行完成。 1.离线安装ffmpeg 看网上许多教程&#xff0c;ffmpeg可完成视频格…

【工具】笔记软件测评(简单)

介绍 笔记软件测评 印象笔记 ── ❌开源、❌markdown&#xff08;不好用&#xff09;、❌本地存储 臭名昭著&#xff0c;被资本搞烂的理想。 notion ── ❌开源、❌本地存储、✔️数据导出&#xff1a;PDF、HTML、Markdown & CSV &#xff08;include subpages&#xf…

重回利润增长,涪陵榨菜为何能跑赢周期?

2022年消费市场持续低迷&#xff0c;疫情寒冬之下&#xff0c;不少食品快消企业均遭遇严重的业绩下滑&#xff0c;但一年里不断遭遇利空打击的“榨菜茅”涪陵榨菜&#xff0c;不仅安然躲过“酸菜劫”、走出“钠”争议&#xff0c;而且顺利将产品价格提起来&#xff0c;并在寒冬…

C++基础篇(一)-- 简单入门

C 语言是在优化 C 语言的基础上为支持面向对象的程序设计而研制的一个通用目的的程序设计语言。在后来的持续研究中&#xff0c;C 增加了许多新概念&#xff0c;例如虚函数、重载、继承、标准模板库、异常处理、命名空间等。 C 语言的特点主要表现在两个方面&#xff1a;全面兼…

CSS的背景版块知识

&#x1f60a;博主页面&#xff1a;鱿年年 &#x1f449;博主推荐专栏&#xff1a;《WEB前端》&#x1f448; ​&#x1f493;博主格言&#xff1a;追风赶月莫停留&#xff0c;平芜尽处是春山❤️ 目录 前言 一、背景颜色 二、背景图片 三、背景平铺 四、背景图片位置…

ATTCK v10版本战术介绍—持久化(二)

一、引言在前几期文章中我们介绍了ATT&CK中侦察、资源开发、初始访问、执行战术、持久化战术&#xff08;一&#xff09;知识&#xff0c;本期我们为大家介绍ATT&CK 14项战术中持久化战术&#xff08;二&#xff09;涉及的6项子技术&#xff0c;后续会陆续介绍其他战术…

魔兽世界335 自动加入公会教程

最近遇到新人进游戏不能自动加入公会的问题&#xff0c;论坛找了好久也没有找到解决办法。自己摸索后发现是核心的问题&#xff0c;下面教程开始1.利用GM账号进游戏&#xff0c;分别创建LM、BL角色&#xff0c;利用GM命令创建公会举例 LM角色名字&#xff1a;暴风 BL角色名字&a…

开发手册——一、编程规约_4.OOP规约

这篇文章主要梳理了在java的实际开发过程中的编程规范问题。本篇文章主要借鉴于《阿里巴巴java开发手册终极版》 下面我们一起来看一下吧。 1. 【强制】避免通过一个类的对象引用访问此类的静态变量或静态方法&#xff0c;无谓增加编译器解析成 本&#xff0c;直接用类名来访…

聚观早报 |支付宝与阿里合作推出支付芯;多多视频DAU峰值破1.5亿

今日要闻&#xff1a;支付宝与阿里合作推出支付芯&#xff1b;保时捷中国召回Panamera系列汽车&#xff1b;「多多视频」DAU峰值破1.5亿&#xff1b;苏州立法禁止大数据“杀熟”&#xff1b;特斯拉投资者日首次开幕支付宝与阿里合作推出支付芯 3 月 2 日消息&#xff0c;支付宝…

taobao.item.sku.update( 更新SKU信息 )

&#xffe5;开放平台免费API必须用户授权 *更新一个sku的数据 *需要更新的sku通过属性properties进行匹配查找 *商品的数量和价格必须大于等于0 *sku记录会更新到指定的num_iid对应的商品中 *num_iid对应的商品必须属于当前的会话用户 公共参数 请求地址: HTTP地址 http://gw.…

【C++修炼之路】23.哈希封装unordered系列

每一个不曾起舞的日子都是对生命的辜负 哈希封装unordered系列前言一.封装的迭代器二.改良后的HashTable.h三.封装的UnorderedSet.h四.封装的UnorderedMap.h五.Test.cpp及测试结果前言 unordered_map、unordered_set与map、set的区别是unoedered系列无序&#xff0c;除此之外功…

MD(消息摘要)、MAC(消息认证码)、数字签名的区别

MD(消息摘要&#xff09;、MAC(消息认证码&#xff09;、数字签名的区别 1.MD(消息摘要&#xff09;-散列算法 摘要是哈希值&#xff0c;我们通过散列算法⽐如MD5算法就可以得到这个哈希值。摘要只是⽤于验证数据完整性和唯⼀性的哈希值&#xff0c;不管原始数据是什么样的&a…

【json代码diff效果展示】vue项目 手动实现高仿github的内容diff效果

文章目录1-1 vue-code-diff业务需求 &#xff1a; 思考&#xff1a; 对比两个json字符串&#xff0c;维护增删改的三个数组 遍历&#xff0c;进行三四五次if判断进入不同数组&#xff0c;渲染页面不对呀&#xff0c;数据展示&#xff0c;怎么根据json对应键展示字段呢&#xf…

Linux基础命令-gdisk使用GPT类型创建分区

文章目录 一 命令介绍 二 MBR和GPT的区别 MBR GPT 三 命令语法 四 基本参数 1 常用参数 2 操作菜单说明 五 参考实例 1 对磁盘设备进行分区 2 查看磁盘的所有分区表 命令总结 一 命令介绍 NAME gdisk - Interactive GUID partition table (GPT) manipulato…