链式结构实现队列

链式结构实现队列

    • 1.队列
      • 1.1队列的概念及结构
      • 1.2队列的实现
    • 2. 队列的各种函数实现
    • 3. 队列的全部代码实现

1.队列

1.1队列的概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出
FIFO(First In First Out)的原则

入队列:进行插入操作的一端称为队尾

出队列:进行删除操作的一端称为队头

如图所示:
在这里插入图片描述

1.2队列的实现

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
在这里插入图片描述

2. 队列的各种函数实现

首先,我们先定义一个栈的结构

typedef int QDataType;//节点的结构
typedef struct QueueNode
{QDataType data;struct QueueNode* next;
}QNode;//链表的结构
typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;

这里我们定义了两个结构体,这是因为在尾插的时候需要一个尾指针,如果每次尾插的时候都要遍历找尾效率太低,所以,我们可以定义一个尾指针,在头删的时候需要一个头指针,这个size其实可以加上有也可以不加,但是不加上的话求队列长度的时候需要遍历,比较麻烦,多个数据共同管理这个队列,所以,我们可以封装成一个结构体来管理这个队列。

初始化队列

void QueueInit(Queue* pq)
{aseert(pq);pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}

销毁队列

void QueueDestroy(Queue* pq)
{assert(pq);QNode* pcur = pq->phead;while (pcur){QNode* next = pcur->next;free(pcur);pcur = next;}pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}

因为,队列中的每个节点的空间都是动态开辟的,所以在用完队列后要及时释放动态开辟的每一个节点。

队尾入队列

void QueuePush(Queue* pq,QDataType x)
{assert(pq);QNode* newcode = QueueBuyNode(x);if (pq->phead == NULL){assert(pq->ptail == NULL);//防止一个为空一个不为空的情况pq->phead = pq->ptail = newcode;}else{pq->ptail->next = newcode;pq->ptail = pq->ptail->next;}pq->size++;
}

这里也可以不把申请节点的代码单独写成一个函数,因为这里只有这一个地方会用到申请节点的操作,但是还是建议封装成一个函数,一方面可以提高代码的可读性,另一方面可以在一定程度上避免代码出错。

这里的assert(pq->ptail == NULL);这句代码主要时为了防止自己的代码写错,造成一个为空一个不为空的情况,所以也可以不写,保证写代码的时候细心一点就可以了。

申请一个节点

QNode* QueueBuyNode(QDataType x)
{c* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");exit(1);}newnode->data = x;newnode->next = NULL;
}

注意:这里是申请一个节点,所以要用定义队列节点的结构体类型 QNode,而不是管理队列的结构题类型

队头出队列

void QueuePop(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));if (pq->phead->next == NULL){pq->phead = NULL;pq->ptail = NULL;}else{QNode* next = pq->phead->next;free(pq->phead);pq->phead =next;}pq->size--;
}

这里的队头出数据也就是头删操作,要注意当删除的链表元素只剩一个时,这里的头指针和尾指针同时指向这一个节点,当删除这个节点的时候,头指针和尾指针都会改变,所以,最好单独处理一下。

因为当只有一个节点的时候执行删除操作后,头指针会变成空,所以我们可以在头指针变成空的时候也把尾指针变成空,所以,这个代码也可以这样写。

void QueuePop(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));QNode* next = pq->phead->next;free(pq->phead);pq->phead = next;if (pq->phead == NULL){pq->ptail = NULL;}pq->size--;
}

获取队列头部元素

QDataType QueueFront(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->phead->data;
}

想要获取队头元素,只需要返回队头指针指向的元素的值

获取队列尾部元素

QDataType QueueBack(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->ptail->data;
}

想要获取队尾元素,只需要返回队尾指针指向的元素的值

获取队列中有效元素个数

int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}

这里只需要返回控制队列结构里面的size就可以了,如果不把size封装结构体里面就需要遍历链表求队列元素个数,不但麻烦,效率也低。

检测队列是否为空,如果为空返回非零结果,如果非空返回0

bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL && pq->ptail == NULL;
}

当头指针和尾指针同时指向空的时候,链表一定为空。

3. 队列的全部代码实现

Queue.h

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>typedef int QDataType;//节点的结构
typedef struct QueueNode
{QDataType data;struct QueueNode* next;
}QNode;//链表的结构
typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;// 初始化队列
void QueueInit(Queue* pq);//销毁队列
void QueueDestroy(Queue* pq);//队尾入队列
void QueuePush(Queue* pq, QDataType x);// 队头出队列
void QueuePop(Queue* pq);//获取队列头部元素
QDataType QueueFront(Queue* pq);// 获取队列队尾元素
QDataType QueueBack(Queue* pq);//获取队列中有效元素个数
int QueueSize(Queue* pq);//检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* pq);

Queue.c

#include "Queue.h"// 初始化队列
void QueueInit(Queue* pq)
{assert(pq);pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}//销毁队列
void QueueDestroy(Queue* pq)
{assert(pq);QNode* pcur = pq->phead;while (pcur){QNode* next = pcur->next;free(pcur);pcur = next;}pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}QNode* QueueBuyNode(QDataType x)
{QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");exit(1);}newnode->data = x;newnode->next = NULL;return newnode;
}//队尾入队列
void QueuePush(Queue* pq,QDataType x)
{assert(pq);QNode* newcode = QueueBuyNode(x);if (pq->phead == NULL){assert(pq->ptail == NULL);pq->phead = pq->ptail = newcode;}else{pq->ptail->next = newcode;pq->ptail = pq->ptail->next;}pq->size++;
}// 队头出队列
void QueuePop(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));if (pq->phead->next == NULL){pq->phead = NULL;pq->ptail = NULL;}else{QNode* next = pq->phead->next;free(pq->phead);pq->phead =next;}pq->size--;
}//获取队列头部元素
QDataType QueueFront(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->phead->data;
}// 获取队列队尾元素
QDataType QueueBack(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->ptail->data;
}//获取队列中有效元素个数
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL && pq->ptail == NULL;
}

Test.c

#include "Queue.h"int main()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);printf("size : %d\n",QueueSize(&q));while (!QueueEmpty(&q)){printf("%d ", QueueFront(&q));QueuePop(&q);}printf("\n");QueueDestroy(&q);return 0;
}

因为队列是后进先出的,所以要访问队列里面的元素时,必须要把队列当前元素取出才能访问下一个元素,每可以看到在打印队列里面的内容时,会把队列变成空,那么队列里面的内容就没有了,但时这也是实际当中的需求,所以不会有什么影响。

运行结果如图:
在这里插入图片描述

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

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

相关文章

Python 修改window桌面背景图片

本篇为Python 修改window桌面背景图片&#xff0c;修改背景图片需要利用windows提供的api&#xff0c;以操作电脑原有功能修改背景图片。 引入类库 首先需要引入相应类库。 示例如下&#xff1a; import win32api import win32con import win32gui 修改背景图片 修改背景图…

.NET Core WebAPI中使用Log4net记录日志

一、安装NuGet包 二、添加配置 // log4net日志builder.Logging.AddLog4Net("CfgFile/log4net.config");三、配置log4net.config文件 <?xml version"1.0" encoding"utf-8"?> <log4net><!-- Define some output appenders -->…

python-自动化篇-办公-将PDF文件转存为图片

因工作中的某些奇葩要求&#xff0c;需要将PDF文件的每页内容转存成按顺序编号的图片。用第三方软件或者在线转换也可以&#xff0c;但批量操作还是Python方便&#xff0c;所谓搞定办公自动化&#xff0c;Python出山&#xff0c;一统天下&#xff1b;Python出征&#xff0c;寸草…

Kubernetes实战:通过ClusterIP方式访问springboot服务

目录 一、准备工作1.1、yaml文件编写 二、创建k8s Service参考资料 一、准备工作 1.1、yaml文件编写 创建kubernets-discovery-service_service.yaml文件&#xff0c;yaml文件内容如下 apiVersion: v1 kind: Service metadata:name: kubernets-discovery-servicenamespace: …

机器学习中7种常用的线性降维技术总结

上篇文章中我们主要总结了非线性的降维技术&#xff0c;本文我们来总结一下常见的线性降维技术。 1、Principal Component Analysis (PCA) Principal Component Analysis (PCA) 是一种常用的降维技术&#xff0c;用于将高维数据集转换为低维表示&#xff0c;同时保留数据集的…

高校疫情防控系统的全栈开发实战

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

Fiddler 无法抓包手机 https 报文的解决方案来啦!!

解决手机https无法抓包的问题 当你测试App的时候&#xff0c;想要通过Fiddler/Charles等工具抓包看下https请求的数据情况&#xff0c;发现大部分的App都提示网络异常/无数据等等信息 这时候怎么解决呢&#xff1f; 以软件测试面试提刷题APP为例&#xff1a; Fiddler上的显示…

vue实现多个下拉框联动(一)

要实现Vue3中多个下拉框的联动&#xff0c;可以使用v-model指令和watch特性来实现。 首先&#xff0c;在Vue组件中定义多个下拉框的数据和选项列表&#xff1a; <template><div><select v-model"selectedOption1"><option v-for"option …

蓝桥杯 星期计算

思路1 由于2022太大&#xff0c;用double来存储&#xff0c;即(52022 % 7) % 7即可 int num 5;int t (int)(Math.pow(20,22)%7);num t;num%7;System.out.println(num1);思路2 你需要知道 (a * b ) % p a % p * b % p Scanner scan new Scanner(System.in);int num 1;for…

深入解析ESP32C3(3)- bootloader启动流程

ESP32C3启动流程可以分为如下3 个步骤&#xff1a; 一级引导程序(PBL)&#xff1a;被固化在了ESP32-C3 内部的ROM 中&#xff0c;它会从flash 的0x0 偏移地址处加载二级引导程序至RAM (IRAM & DRAM) 中。二级引导程序(SBL)&#xff1a;从flash 中加载分区表和主程序镜像至…

python解构赋值详解(包含leetcode226.翻转二叉树题目讲解以及python代码)

目录 一、背景 1.1问题 1.2原因 二、解构赋值 2.1定义 2.2解题应用 2.2.1翻转二叉树 2.2.2 思路以及代码 一、背景 1.1问题 在写二叉树相关代码赋值的时候发现这样的写法&#xff0c;担心会发生这样的情况&#xff1a;先把node.right的值给node.left&#xff0c;在把…

【C++搜索】DFS:排列与组合

1. 题目描述 排列与组合是常用的数学方法&#xff0c;桐桐刚刚学会了全排列&#xff0c;就想试试组合&#xff0c;组合就是从n个元素中抽出r个元素&#xff08;不分顺序且r≤n&#xff09;&#xff0c;我们可以简单地将n个元素理解为自然数1&#xff0c;2&#xff0c;…&…

MongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(3)-系统数据集合设计

前言 前几章教程我们把ToDoList系统的基本框架搭建好了&#xff0c;现在我们需要根据我们的需求把ToDoList系统所需要的系统集合&#xff08;相当于关系型数据库中的数据库表&#xff09;。接下来我们先简单概述一下这个系统主要需要实现的功能以及实现这些功能我们需要设计那些…

光伏计算数据的意义

随着全球气候变化的日益严重&#xff0c;可再生能源的发展已成为应对这一挑战的关键。其中&#xff0c;光伏能源作为一种清洁、可持续的能源形式&#xff0c;日益受到各国的重视。然而&#xff0c;要充分利用光伏能源&#xff0c;我们需要深入理解光伏计算数据&#xff0c;并明…

互联网加竞赛 基于设深度学习的人脸性别年龄识别系统

文章目录 0 前言1 课题描述2 实现效果3 算法实现原理3.1 数据集3.2 深度学习识别算法3.3 特征提取主干网络3.4 总体实现流程 4 具体实现4.1 预训练数据格式4.2 部分实现代码 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习机器视觉的…

【RL】Value Iteration and Policy Iteration(利用迭代算法求解贝尔曼最优等式)

Lecture 4: Value Iteration and Policy Iteration Value Iteration Algorithm 对于Bellman最优公式&#xff1a; v f ( v ) m a x π ( r γ P π v ) \mathbf{v} f(\mathbf{v}) max_{\pi}(\mathbf{r} \gamma \mathbf{P}_{\pi} \mathbf{v}) vf(v)maxπ​(rγPπ​v) …

『运维备忘录』之 Sed 命令详解

运维人员不仅要熟悉操作系统、服务器、网络等只是&#xff0c;甚至对于开发相关的也要有所了解。很多运维工作者可能一时半会记不住那么多命令、代码、方法、原理或者用法等等。这里我将结合自身工作&#xff0c;持续给大家更新运维工作所需要接触到的知识点&#xff0c;希望大…

【大厂AI课学习笔记】【2.1 人工智能项目开发规划与目标】(1)发现与明确问题

抱歉&#xff0c;过春节这几天&#xff0c;没有更新。赶紧续上。 人就是这样&#xff0c;放假之前呢&#xff0c;想着趁着这个假期&#xff0c;把很多之前没有做好的事情&#xff0c;都梳理好&#xff0c;该补的也补上&#xff0c;结果一个假期就这样过去了&#xff0c;很多想…

单反相机用sd卡还是cf卡?相机cf卡和sd卡区别

随着科技的进步&#xff0c;单反相机成为了摄影爱好者和专业摄影师的必备工具。而在选择单反相机存储介质时&#xff0c;CF卡和SD卡成为了两种常见的选择。它们各有优缺点&#xff0c;适用于不同的摄影需求和场景。本文将深入探讨单反相机使用SD卡还是CF卡的问题&#xff0c;并…

stm32:pwm output模块,记录一下我是用smt32,输出pwm波的记录--(实现--重要)

我是实现了输出pwm波&#xff0c;频率固定&#xff0c;占空比可以不断调整的方法&#xff0c;将PA0接到示波器上&#xff0c;可以看到是一个标准的PWM波&#xff0c;如图下面示波器图。 1&#xff0c;首先是ioc的配置 我刚开始设置的分频的倍数是7199&#xff0c;使得分频的太…