数据结构与算法学习笔记三---队列的链式存储表示和实现(C++)

news2024/11/17 22:44:12

目录

前言

1.队列的概念

2.队列的表示和实现

1.定义

2.初始化

​编辑

3.销毁队列

4.清空队列

5.队列判空

6.队列长度

7.获取队头元素

8.入队

9.出队

10.遍历

11.完整代码


前言

    这篇博客主要讲的是对队列的链式存储。

1.队列的概念

        队列是一种访问受限的线性表。仅允许在表的一端进行插入操作,在表的另一端进行删除操作。和日常生活中的排队是一致的,最先进入队列的元素最早离开。插入的一端称为队头(front),删除的一端称为队尾(rear)。

        队列的示意图如下:

        图1.队列的示意图

2.队列的表示和实现

1.定义

        我们使用指针我们使用指向结点元素的指针分别表示队列的队头和队尾。

typedef int ElemType;
typedef struct QNode{
    ElemType data;
    struct QNode * next;
}QNode,*QueuePtr;

typedef struct {
    QueuePtr  front,rear;
}LinkQueue;

2.初始化

        链队列的初始化是构造一个只有一个头结点的空队,使队头和队尾指针指向次节点,并将节点的指针置为NULL。如下图2所示。

        图2.链队列的操作示意图

队列的初始化代码如下:

//初始化
Status initLinkQueue(LinkQueue *queue) {
    queue->front = queue->rear = new QNode;
    if (!queue->front) {
        return 0; // 内存分配失败
    }
    queue->front->next = NULL;
    return 1;
}

3.销毁队列

        为链队列增加销毁方法相对简单,只需释放链表中的所有节点即可。

// 销毁队列
Status destroyQueue(LinkQueue *queue) {
    QueuePtr p, q;
    p = queue->front;
    while (p) {
        q = p;
        p = p->next;
        delete q;
    }
    queue->front = queue->rear = NULL;
    return 1;
}

4.清空队列

        清空队列的方法类似于销毁队列,但是不释放头结点。可以通过循环释放除头结点外的所有节点,并将头结点的 frontrear 指针重新指向头结点。

// 清空队列
Status clearQueue(LinkQueue *queue) {
    QueuePtr p, q;
    p = queue->front->next; // 从头结点的下一个节点开始遍历
    while (p) {
        q = p;
        p = p->next;
        delete q;
    }
    queue->front->next = NULL; // 确保头结点的 next 指针为空,即队列为空
    // 注意:这里不释放 queue->front,因为它是队列的永久头节点
    queue->rear = queue->front; // 重新设置队尾指针
    return 1;
}

5.队列判空

        当对头和队尾相同的时候,队列为空。

//判空
Status isEmpty(LinkQueue *queue) {
    return queue->front->next == NULL; // 如果头指针的下一个节点为空,则队列为空
}

6.队列长度

        可以通过遍历队列中的元素来计算队列的长度。

// 求队列长度
int queueLength(LinkQueue *queue) {
    int length = 0;
    QueuePtr p = queue->front->next; // 从头结点的下一个节点开始遍历
    while (p) {
        length++;
        p = p->next;
    }
    return length;
}

7.获取队头元素

              获取链队列头元素的时候,首先要判断链队列是否是空队列,如果队列为空,不操作;否则,获取队列的头结点的下一个元素即可(因为我们这里用到了头结点,头结点的数据域是不可用使用的)。

//获取队列头元素
Status getHead(LinkQueue *queue, ElemType *e) {
    if (queue->front == queue->rear) {
        return 0; // 队列为空
    }
    *e = queue->front->next->data;
    return 1;
}

8.入队

        入队的过程其实是生成一个新的节点,并且修改尾指针,并且把尾指针设置称为新的节点。

//入队
Status enQueue(LinkQueue *queue, ElemType e) {
    QueuePtr p = new QNode;
    if (!p) {
        return 0; // 内存分配失败
    }
    p->data = e;
    p->next = NULL;
    queue->rear->next = p;
    queue->rear = p;
    return 1;
}

9.出队

        连队列的出队首先是判断链队列是否为空,如果为空,则不操作;否则取出表头元素,修改头指针。

//出队
Status deQueue(LinkQueue *queue, ElemType *e) {
    if (queue->front == queue->rear) {
        return 0; // 队列为空
    }
    QueuePtr p = queue->front->next;
    *e = p->data;
    queue->front->next = p->next;
    if (queue->rear == p) {
        queue->rear = queue->front; // 如果出队后队列为空,修改队尾指针
    }
    delete p;
    return 1;
}

10.遍历

        这里当队头和队尾相同的时候,链队列即为空队列。

// 遍历队列
void traverseLinkQueue(LinkQueue *queue) {
    if (isEmpty(queue)) {
        cout << "Queue is empty." << endl;
        return;
    }
    QueuePtr p = queue->front->next; // 从头结点的下一个节点开始遍历
    while (p) {
        cout << p->data << " "; // 输出队列中的元素
        p = p->next;
    }
    cout << endl; // 输出完毕后换行
}

11.完整代码

#include <iostream>
using namespace std;

typedef int ElemType;
typedef int Status;
typedef struct QNode {
    ElemType data;
    struct QNode *next;
} QNode, *QueuePtr;

typedef struct {
    QueuePtr  front, rear;
} LinkQueue;

//初始化
Status initLinkQueue(LinkQueue *queue) {
    queue->front = queue->rear = new QNode;
    if (!queue->front) {
        return 0; // 内存分配失败
    }
    queue->front->next = NULL;
    return 1;
}
// 清空队列
Status clearQueue(LinkQueue *queue) {
    QueuePtr p, q;
    p = queue->front->next; // 从头结点的下一个节点开始遍历
    while (p) {
        q = p;
        p = p->next;
        delete q;
    }
    queue->front->next = NULL; // 确保头结点的 next 指针为空,即队列为空
    // 注意:这里不释放 queue->front,因为它是队列的永久头节点
    queue->rear = queue->front; // 重新设置队尾指针
    return 1;
}

//判空
Status isEmpty(LinkQueue *queue) {
    return queue->front->next == NULL; // 如果头指针的下一个节点为空,则队列为空
}
// 求队列长度
int queueLength(LinkQueue *queue) {
    int length = 0;
    QueuePtr p = queue->front->next; // 从头结点的下一个节点开始遍历
    while (p) {
        length++;
        p = p->next;
    }
    return length;
}



//入队
Status enQueue(LinkQueue *queue, ElemType e) {
    QueuePtr p = new QNode;
    if (!p) {
        return 0; // 内存分配失败
    }
    p->data = e;
    p->next = NULL;
    queue->rear->next = p;
    queue->rear = p;
    return 1;
}

//出队
Status deQueue(LinkQueue *queue, ElemType *e) {
    if (queue->front == queue->rear) {
        return 0; // 队列为空
    }
    QueuePtr p = queue->front->next;
    *e = p->data;
    queue->front->next = p->next;
    if (queue->rear == p) {
        queue->rear = queue->front; // 如果出队后队列为空,修改队尾指针
    }
    delete p;
    return 1;
}

//获取队列头元素
Status getHead(LinkQueue *queue, ElemType *e) {
    if (queue->front == queue->rear) {
        return 0; // 队列为空
    }
    *e = queue->front->next->data;
    return 1;
}
// 遍历队列
void traverseLinkQueue(LinkQueue *queue) {
    if (isEmpty(queue)) {
        cout << "Queue is empty." << endl;
        return;
    }
    QueuePtr p = queue->front->next; // 从头结点的下一个节点开始遍历
    while (p) {
        cout << p->data << " "; // 输出队列中的元素
        p = p->next;
    }
    cout << endl; // 输出完毕后换行
}

int main(int argc, const char * argv[]) {
    LinkQueue queue;
    cout<<"链队列初始化中..."<<endl;
    if (initLinkQueue(&queue)) {
        cout<<"链队列初始化成功"<<endl;
    }
    cout<<"链队列判空和长度..."<<endl;
    cout<<"队列长度:"<<queueLength(&queue)<<endl;
    if (isEmpty(&queue)) {
        cout<<"队列为空"<<endl;
    }
    // 入队
    enQueue(&queue, 1);
    enQueue(&queue, 2);
    enQueue(&queue, 3);
    traverseLinkQueue(&queue);
    ElemType head;
    if (getHead(&queue, &head)) {
        cout<<"队头指针:"<<head<<endl;
    }
    cout<<"出队测试......"<<endl;
    int element;
    if (deQueue(&queue, &element)) {
        cout<<"出队列成功,出队元素:"<<element<<endl;
    }
    cout<<"出队之后的队列......"<<endl;
    traverseLinkQueue(&queue);
    cout<<"清空队列......"<<endl;
    if (clearQueue(&queue)) {
        cout<<"队列清空成功,队列长度:"<<queueLength(&queue)<<endl;
    }
    // 出队并打印
    ElemType e;
    while (!isEmpty(&queue)) {
        deQueue(&queue, &e);
        cout << e << " ";
    }
    cout << endl;
    
    return 0;
}

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

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

相关文章

如何将一个VPS上的网站全部迁移至另外一个VPS服务器

最近我们老的VPS即将到期&#xff0c;由于近期Hostease的VPS活动力度较大&#xff0c;我们购买了Hostease的VPS&#xff0c;购买后需要将原服务器的所有网站迁移到Hostease提供的VPS中。在Hostease技术人员的帮助下&#xff0c;我们成功进行了迁移&#xff0c;下面我就介绍此次…

酷开科技丨母亲节,别让有爱瞬间轻易溜走

在母亲节这个充满温情的节日里&#xff0c;酷开科技以“健健康康才能长长久久”为主题&#xff0c;推出了一系列关怀活动&#xff0c;旨在通过科技的力量&#xff0c;提升母亲们的身体素质和生活质量&#xff0c;同时也为儿女们提供了表达孝心和关怀的机会。 酷开系统特别上线…

域基础-NTLM协议

简介 NTLM(New Technology LAN Manager)协议是微软用于Windows身份验证的主要协议之一。继SMB、LM协议之后微软提出了NTLM协议&#xff0c;这一协议安全性更高&#xff0c;不仅可以用于工作组中的机器身份验证&#xff0c;又可以用于域环境身份验证&#xff0c;还可以为SMB、H…

深入解析RedisSearch:全文搜索的新维度

码到三十五 &#xff1a; 个人主页 在当今的数据时代&#xff0c;信息的检索与快速定位变得尤为关键。Redis&#xff0c;作为一个高性能的内存数据库&#xff0c;已经在缓存和消息系统中占据了重要地位。然而&#xff0c;Redis并不直接支持复杂的搜索功能。为了填补这一空白&am…

Android AOSP Ubuntu源码编译电脑卡顿问题定位解决

文章目录 问题概述分析问题解决问题查看交换分区创建交换分区删除交换分区调整交换分区的活跃度 问题概述 开发SystemUI时&#xff0c;使用内存为16G的主机&#xff0c;Ubuntu 20.04的系统编译SystemUI的源码&#xff0c;编译的过程中发现电脑卡顿&#xff0c;鼠标不能移动。必…

渗透思考题

一&#xff0c;尝试登录。 客户端对密码进行哈希处理并缓存密码hash&#xff0c;丢弃实际的明文密码&#xff0c;然后将用户名发送到服务器&#xff0c;发起认证请求 密文存储位置&#xff1a;数据库文件位于C:WindowsSystem32configsam&#xff0c;同时挂载在注册表中的HKLMSA…

台阶仪测量膜厚原理及优势

台阶仪&#xff0c;也称为探针式轮廓仪或接触式表面轮廓测量仪&#xff0c;主要用于台阶高、膜层厚度、表面粗糙度等微观形貌参数的测量。 台阶仪的工作原理 台阶仪的核心部件是一个精密的触针或探针&#xff0c;它被安装在一个高度可调的支架上。当触针沿被测表面轻轻滑过时…

vue阶段案例,练习filter、map、forEach,双向绑定,三元表达式,以及图片滚动,文字跳动等等。

阶段案例 通过案例来练习双向绑定&#xff0c;三元表达式&#xff0c;以及图片滚动&#xff0c;文字跳动等等。 代码如下&#xff1a; <template><table class"bjtp" ><div class"title" >{{title}}</div><div class"s…

ACM实训冲刺第四天

【碎碎念】最近的任务有点繁重&#xff0c;所以考虑到实际情况&#xff0c;视频学习决定放置一段时间&#xff0c;重点是学校的实训练习题&#xff0c;对于我而言&#xff0c;目标不是优秀/良好&#xff0c;综合考虑我的实际情况&#xff0c;保佑我及格、顺利通过就可&#xff…

机器学习算法应用——神经网络回归任务、神经网络分类任务

神经网络回归任务&#xff08;4-3&#xff09; 神经网络回归任务&#xff0c;通常指的是使用神经网络模型进行回归分析。回归分析是一种统计学方法&#xff0c;用于研究一个或多个自变量&#xff08;预测变量&#xff09;与一个因变量&#xff08;响应变量&#xff09;之间的关…

node pnpm修改默认包的存储路径

pnpm与npm的区别 PNPM和NPM是两个不同的包管理工具。 NPM&#xff08;Node Package Manager&#xff09;是Node.js的官方包管理工具&#xff0c;用于安装、发布和管理Node.js模块。NPM将包安装在项目的node_modules目录中&#xff0c;每个包都有自己的依赖树。 PNPM&#xf…

c++ STL 之栈—— stack 详解

vector 是 stl 的一个关联容器,名叫“栈”&#xff0c;何为“栈”&#xff1f;其实就是一个数组&#xff0c;但有了数组何必还需栈&#xff0c;这是一个高深的问题。 一、简介 1. 定义 栈&#xff0c;是一个柔性数组&#xff08;可变长数组&#xff09;&#xff0c;可以变大变小…

【教程向】从零开始创建浏览器插件(三)解决 Chrome 扩展中弹出页面、背景脚本、内容脚本之间通信的问题

第三步&#xff1a;解决 Chrome 扩展中弹出页面、背景脚本、内容脚本之间通信的问题 Chrome 扩展开发中&#xff0c;弹出页面&#xff08;Popup&#xff09;、背景脚本&#xff08;Background Script&#xff09;、内容脚本&#xff08;Content Script&#xff09;各自拥有独立…

设计模式2——原则篇:依赖倒转原则、单一职责原则、合成|聚合复用原则、开放-封闭原则、迪米特法则、里氏代换原则

设计模式2——设计原则篇 目录 一、依赖倒转原则 二、单一职责原则&#xff08;SRP&#xff09; 三、合成|聚合复用原则&#xff08;CARP&#xff09; 四、开放-封闭原则 五、迪米特法则&#xff08;LoD&#xff09; 六、里氏代换原则 七、接口隔离原则 八、总结 一、依赖…

R语言数据探索与分析-碳排放分析预测

# 安装和加载需要的包 install.packages("readxl") install.packages("forecast") install.packages("ggplot2") library(readxl) library(forecast) library(ggplot2)# 数据加载和预处理 data <- read_excel("全年数据.xlsx") co…

有哪些是618必买的数码好物,这几款千万别错过

备受瞩目的618购物节即将拉开帷幕&#xff0c;身为数码领域的资深发烧友&#xff0c;我迫不及待地要为大家呈现一系列精心挑选的数码产品。无论您是热衷于追求科技尖端的先锋者&#xff0c;还是希望用智能设备为生活增添一抹亮色的品味人士&#xff0c;这里总有一款能让您心动的…

【python】python中的argparse模块,教你如何自定义命令行参数

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

ARM基于DWT实现硬件延时(GD32)

软件延时的缺点 软件延时的精度差&#xff0c;受系统主频影响&#xff0c;调教困难 硬件延时 DWT数据跟踪监视点单元硬件延时 硬件延时实现代码 delay.c #include <stdint.h> #include "gd32f30x.h"/** *****************************************************…

【算法入门赛】A.坐标变换(推荐学习)C++题解与代码

比赛链接&#xff1a;https://www.starrycoding.com/contest/8 题目描述 武汉市可以看做一个二维地图。 牢 e e e掌握了一项特异功能&#xff0c;他可以“瞬移”&#xff0c;每次瞬移需要分别设定 x x x和 y y y的偏移量 d x dx dx和 d y dy dy&#xff0c;瞬移完成后位置会…

JMeter 如何应用于 WebSocket 接口测试

WebSocket: 实时双向通信的探索及利用 JMeter 进行应用性能测试 WebSocket 是一项使客户端与服务器之间可以进行双向通信的技术&#xff0c;适用于需要实时数据交换的应用。为了衡量和改进其性能&#xff0c;可以通过工具如 JMeter 进行测试&#xff0c;但需要先对其进行适配以…