数据结构:线性表(队列实现)

1. 队列的概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除操作的特殊线性表,队列具有先进先出(FIFO)的特性.
进行插入操作的一端称为队尾;进行删除操作的一端叫做队头

在这里插入图片描述

队列应用于

  1. 解决公平性排队(抽号机)
  2. 广度优先遍历(BFS)

2. 队列的定义

和栈一样,队列也可以使用两种物理结构进行存储:数组存储和链表存储
但是更推荐使用链表进行实现,链表尾插头删,相比于数组尾插头删所消耗的时间要小很多

注: 如果实现循环队列,更推荐使用数组

  • 单链表实现队列的头删尾插图示:
    在这里插入图片描述
    在这里插入图片描述

  • 队列的链式实现

typedef int QDataType;// 链式结构表示队列
typedef struct QListNode
{struct QListNode* next;QDataType data;
}QNode;// 队列的结构
typedef struct Queue
{QNode* front;    //指向队列头QNode* rear;     //指向队列尾int size;        //记录队列的元素个数
}Queue;
  1. 队列的每个结点使用链表结点
  2. 同时,在单链表的基础上,队列还多加了两个指针指向头尾,方便使用 O ( 1 ) O(1) O(1)的时间复杂度找到队列的头和尾,进行头删尾插
  • 队列相关接口函数
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType x);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列尾部元素
QDataType QueueBack(Queue* q);
// 获取队列有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空, 如果为空返回非零结果, 如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);

3. 队列的实现

3.1 初始化队列 (QueueInit)

// 初始化队列
void QueueInit(Queue* q)
{assert(q);  //确保q合法q->front = q->rear = NULL;  //将头和为置为 NULL q->size = 0;
}
  1. 首先确保 q 合法
  2. 将队列中的成员变量初始化, 头尾指针置为 NULL, 队列的大小置为 0

3.2 队尾入队列 (QueuePush)

void QueuePush(Queue* q, QDataType x)
{assert(q);  //确保q合法//创建新结点QNode* newNode = (QNode*)malloc(sizeof(QNode));newNode->data = x;newNode->next = NULL;//入队列if (QueueEmpty(q)){//如果队列为空,直接赋值q->front = q->rear = newNode;}else {//如果队列不为空,直接尾插q->rear->next = newNode;q->rear = newNode;}q->size++;
}
  1. 首先确保 q 合法
  2. 创建新结点
  3. 进行队列的尾插,分为两种情况:队列为空的时候直接赋值;队列不为空的时候正常进行尾插

3.2 队头出队列 (QueuePop)

void QueuePop(Queue* q)
{assert(q);  //确保q合法assert(!QueueEmpty(q)); //确保队列不为空if (q->size == 1){//如果只有一个元素,头删的同时还要将尾指针置空free(q->front);q->front = q->rear = NULL;}else {//如果不止一个元素,则只头删QNode* nextNode = q->front->next;free(q->front);q->front = nextNode;}q->size--;
}
  1. 首先确保 q 合法
  2. 分为三种情况:
    • 队列为空直接返回错误
    • 队列只有一个结点,头尾指针都置空
    • 队列有两个及以上的结点,简单头删

3.3 获取队列头部元素 (QueueTop)

QDataType QueueFront(Queue* q)
{assert(q);  //确保q合法assert(!QueueEmpty(q)); //确保队列不为空return q->front->data;
}

3.4 获取队列尾部元素 (QueueBack)

QDataType QueueBack(Queue* q)
{assert(q);  //确保q合法assert(!QueueEmpty(q)); //确保队列不为空return q->rear->data;
}

3.5 获取队列大小 (QueueSize)

int QueueSize(Queue* q)
{assert(q);  //确保q合法return q->size;
} 

3.6 判断队列是否为空, 如果为空返回非0, 非空返回0 (QueueEmpyt)

int QueueEmpty(Queue* q)
{assert(q);  //确保q合法if (q->size == 0){return 1;}else {return 0;}
}

3.7 销毁队列 (QueueDestroy)

void QueueDestroy(Queue* q)
{assert(q);while(!QueueEmpty(q)){QNode* nextNode = q->front->next;free(q->front);q->front = nextNode;}q->front = q->rear = NULL;q->size = 0;
}
  1. 首先确保 q 合法
  2. 从头遍历队列,依次释放每个结点的空间,注意先要记录当前要销毁结点的下一个结点.

3.8 完整代码

  • Queue.h
#pragma once #include <stdio.h>
#include <stdlib.h>
#include <assert.h>typedef int QDataType;// 链式结构表示队列
typedef struct QListNode
{struct QListNode* next;QDataType data;
}QNode;// 队列的结构
typedef struct Queue
{QNode* front;    //指向队列头QNode* rear;     //指向队列尾int size;        //记录队列的元素个数
}Queue;// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType x);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列尾部元素
QDataType QueueBack(Queue* q);
// 获取队列有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空, 如果为空返回非零结果, 如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
  • Queue.c
#pragma once #include <stdio.h>
#include <stdlib.h>
#include <assert.h>typedef int QDataType;// 链式结构表示队列
typedef struct QListNode
{struct QListNode* next;QDataType data;
}QNode;// 队列的结构
typedef struct Queue
{QNode* front;    //指向队列头QNode* rear;     //指向队列尾int size;        //记录队列的元素个数
}Queue;// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType x);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列尾部元素
QDataType QueueBack(Queue* q);
// 获取队列有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空, 如果为空返回非零结果, 如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
  • test.c
#include "Queue.h"void QueueTest1()
{Queue queue;QueueInit(&queue);QueuePush(&queue, 1);QueuePush(&queue, 2);QueuePush(&queue, 3);QueuePush(&queue, 4);QueuePush(&queue, 5);QueuePop(&queue);QueuePop(&queue);QueuePop(&queue);QueuePop(&queue);QueuePop(&queue);QueuePop(&queue);
}void QueueTest2()
{Queue queue;QueueInit(&queue);QueuePush(&queue, 1);QueuePush(&queue, 2);QueuePush(&queue, 3);QueuePush(&queue, 4);QueuePush(&queue, 5);QueuePush(&queue, 6);while (!QueueEmpty(&queue)){fprintf(stdout, "%d ", QueueFront(&queue));QueuePop(&queue);}printf("\n");}
int main(void)
{//QueueTest1();QueueTest2();return 0;
}

本章完.

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

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

相关文章

反序列化漏洞及漏洞复现

文章目录 渗透测试漏洞原理不安全的反序列化1. 序列化与反序列化1.1 引例1.2 序列化实例1.2.1 定义一个类1.2.2 创建对象1.2.3 反序列化1.2.4 对象注入 2. 漏洞何在2.1 漏洞触发 3. 反序列化漏洞攻防3.1 PHP反序列化实例3.1.1 漏洞利用脚本3.1.2 漏洞利用3.1.3 获取GetShell 3.…

Python网页请求超时如何解决

在进行网络爬虫项目时&#xff0c;我们经常需要发送大量的请求来获取所需的数据。然而&#xff0c;由于网络环境的不稳定性&#xff0c;请求可能会因为超时而失败。请求超时可能导致数据获取不完整&#xff0c;影响爬虫的效率和准确性。此外&#xff0c;频繁的请求超时可能会被…

KNN算法回归问题介绍和实现

上篇博客中&#xff0c;介绍了使用KNN算法实现分类问题&#xff0c;本篇文章介绍使用KNN算法实现回归问题。介绍思路是先使用sklearn包提供的方法实现一个KNN算法的回归问题。再自定义实现一个KNN算法的回归问题工具类。 一、sklearn包使用KNN算法 1. 准备数据 使用sklearn包…

单片机之硬件记录

一、概念 VBAT 当使用电池或其他电源连接到VBAT脚上时&#xff0c;当VDD断电时&#xff0c;可以保存备份寄存器的内容和维持RTC的功能。如果应用中没有使用外部电池&#xff0c;VBAT引脚应接到VDD引脚上。 VCC&#xff1a;Ccircuit 表示电路的意思,即接入电路的电压&#x…

java设计模式,简单工厂和抽象工厂有什么区别?

java设计模式&#xff0c;简单工厂和抽象工厂有什么区别&#xff1f; 简单工厂模式&#xff1a; 这个模式本身很简单而且使用在业务较简单的情况下。一般用于小项目或者具体产品很少扩展的情况&#xff08;这样工厂类才不用经常更改&#xff09;。 它由三种角色组成&#xf…

pip和conda的环境管理,二者到底应该如何使用

关于pip与conda是否能混用的问题&#xff0c;Anaconda官方早就给出了回答 先说结论&#xff0c;如果conda和pip在相同环境下掺杂使用&#xff0c;尤其是频繁使用这两个工具进行包的安装&#xff0c;可能会导致环境状态混乱 就像其他包管理器一样&#xff0c;大部分这些问题均…

Eviews用向量自回归模型VAR实证分析公路交通通车里程与经济发展GDP协整关系时间序列数据和脉冲响应可视化...

全文下载链接&#xff1a;http://tecdat.cn/?p27784 河源市是国务院1988年1月7日批准设立的地级市&#xff0c;为了深入研究河源市公路交通与经济发展的关系&#xff0c;本文选取了1988&#xff0d;2014年河源市建市以来24年的地区生产总值&#xff08;GDP&#xff09;和公路通…

Linux dup dup2函数

/*#include <unistd.h>int dup2(int oldfd, int newfd);作用&#xff1a;重定向文件描述符oldfd 指向 a.txt, newfd 指向b.txt,调用函数之后&#xff0c;newfd和b.txt close&#xff0c;newfd指向a.txtoldfd必须是一个有效的文件描述符 */ #include <unistd.h> #i…

selenium的Chrome116版驱动下载

这里写自定义目录标题 下载地址https://googlechromelabs.github.io/chrome-for-testing/#stable 选择chromedriver 对应的平台和版本 国内下载地址 https://download.csdn.net/download/dongtest/88314387

北斗高精度定位,破解共享单车停车乱象

如今&#xff0c;共享单车已经成为了许多人出行的首选方式&#xff0c;方便了市民们的“最后一公里”&#xff0c;给大家的生活带来了很多便利。然而&#xff0c;乱停乱放的单车也给城市治理带来了难题。在这种情况下&#xff0c;相关企业尝试将北斗导航定位芯片装载到共享单车…

Mysql->Hudi->Hive

一 准备 1.启动集群 /hive/mysql start-all.sh2.启动spark-shell spark-shell \--master yarn \ //--packages org.apache.hudi:hudi-spark3.1-bundle_2.12:0.12.2 \--jars /opt/software/hudi-spark3.1-bundle_2.12-0.12.0.jar \--conf spark.serializerorg.apache.spark.…

【数据结构】双向链表详解

当我们学习完单链表后&#xff0c;双向链表就简单的多了&#xff0c;双向链表中的头插&#xff0c;尾插&#xff0c;头删&#xff0c;尾删&#xff0c;以及任意位置插&#xff0c;任意位置删除比单链表简单&#xff0c;今天就跟着小张一起学习吧&#xff01;&#xff01; 双向链…