队列的深度解析:链式队列的实现

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 队列的深度解析:链式队列的实现

引言

队列是一种广泛应用于计算机科学的数据结构,具有先进先出FIFO)的特性。在许多实际应用中,例如任务调度、缓冲区管理等,队列扮演着重要角色。本文将详细介绍队列的基本概念,并通过链表实现一个简单的队列。

一、基本概念

1.1定义

队列是一种线性数据结构,遵循先进先出(FIFO,First In First Out)的原则。这意味着第一个被插入的元素是第一个被移除的元素。队列模拟了排队现象,新来的人不断加入队列尾部,而位于队列头部的人逐个离开。

如下图所示,我们将队列头部称为“队首”,尾部称为“队尾”,将把元素加入队尾的操作称为“入队”,删除队首元素的操作称为“出队”。

1.2基本操作

队列的主要操作包括:

  • 入队(Push):将一个元素添加到队列的尾部。
  • 出队(Pop):移从队列的头部移除并返回一个元素。
  • 取队首元素(Front):返回队首的元素,但不删除它。
  • 取队尾元素(Back):返回队尾的元素,但不删除它。
  • 队列判空(isEmpty):判断队列中是否有元素。
  • 获取队列长度(Size):获取队列中有效元素个数。

1.3队列的特点

队列的特点包括:

先进先出(FIFO):最先进入的元素最先被移除。

操作限制:只能在队列的头部出队,在尾部入队。

队首元素:队首是当前可以访问和移除的元素。

空队列:队列为空时无法进行出队操作。

动态大小:可以根据需要扩展或收缩。

三、链式队列的实现

1.链表节点的定义

首先,我们定义一个链表节点结构:

typedef int DataType;
//定义节点结构体
typedef struct Node
{
  DataType data;//数据域
  struct Node* next;//指针域
}Node;

2.队列结构的定义

然后,我们定义队列结构,包含队头、队尾指针以及队列长度:

//定义队列结构体
typedef struct Queue
{
  Node* phead;//队头
  Node* ptail;//队尾
  int size;//队列长度
}QU;

3.基本操作

(1).初始化队列

//初始化队列 
void QueueInit(QU* p)
{
  assert(p);
  p->phead = p->ptail = NULL;
  p->size = 0;
}

(2).入队

//创建节点
//Node* CreateNode(DataType x)
//{
//  Node* newnode = (Node*)malloc(sizeof(Node));
//  if (newnode == NULL) {
//    perror("malloc fail");
//    exit(1);
//  }
//  newnode->data = x;
//  newnode->next = NULL;
//  return newnode;
//}
 
//入队列,队尾
void QueuePush(QU* p, DataType x)
{
  assert(p);
  Node* newnode = CreateNode(x);
  if (p->phead == NULL)//队列为空
  {
    p->phead = p->ptail = newnode;
  }
  else//队列不为空
  {
    p->ptail->next = newnode;
    p->ptail = newnode;
  }
  ++p->size;
}

(3).队列判空

//队列判空 
bool QueueEmpty(QU* p)
{
  assert(p);
  return p->phead == NULL;
}

(4).出队

//出队列,队头 
void QueuePop(QU* p)
{
  assert(p);
  assert(!QueueEmpty(p));//队列为空不能出队
  if (p->phead == p->ptail)//只有一个元素时
  {
    free(p->phead);
    p->phead = p->ptail = NULL;
  }
  else
  {
    Node* del = p->phead;
    p->phead = p->phead->next;
    free(del);
  }
  --p->size;
}

(5).取队首元素

//取队头数据 
DataType QueueFront(QU* p)
{
  assert(p);
  assert(!QueueEmpty(p));//队列不能为空
  return p->phead->data;
}

(6).取队尾元素

//取队尾数据 
DataType QueueBack(QU* p)
{
  assert(p);
  assert(!QueueEmpty(p));//队列不能为空
  return p->ptail->data;
}

(7).获取队列长度

//队列长度
int QueueSize(QU* p)
{
  assert(p);
  return p->size;
}

(8).销毁队列

//销毁队列 
void QueueDestroy(QU* p)
{
  assert(p);
  assert(!QueueEmpty(p));//队列不能为空
  Node* pcur = p->phead;
  while (pcur)
  {
    Node* next = pcur->next;
    free(pcur);
    pcur = next;
  }
  p->phead = p->ptail = NULL;
  p->size = 0;
}

四、完整代码

Queue.h

该部分主要包括函数的声明、以及头文件的引用

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int DataType;
//定义节点结构体
typedef struct Node
{
  DataType data;//数据域
  struct Node* next;//指针域
}Node;
//定义队列结构体
typedef struct Queue
{
  Node* phead;//队头
  Node* ptail;//队尾
  int size;//队列长度
}QU;
//初始化队列 
void QueueInit(QU* p); 
//入队列,队尾
void QueuePush(QU* p, DataType x);
//队列判空 
bool QueueEmpty(QU* p);
//出队列,队头 
void QueuePop(QU* p);
//取队头数据 
DataType QueueFront(QU* p);
//取队尾数据 
DataType QueueBack(QU* p);
//队列长度
int QueueSize(QU* p);
//销毁队列 
void QueueDestroy(QU* p);

Queue.c

该部分主要包括函数的定义

#define _CRT_SECURE_NO_WARNINGS
#include"Queue.h"
//初始化队列 
void QueueInit(QU* p)
{
  assert(p);
  p->phead = p->ptail = NULL;
  p->size = 0;
}
 
//创建节点
Node* CreateNode(DataType x)
{
  Node* newnode = (Node*)malloc(sizeof(Node));
  if (newnode == NULL) {
    perror("malloc fail");
    exit(1);
  }
  newnode->data = x;
  newnode->next = NULL;
  return newnode;
}
 
//入队列,队尾
void QueuePush(QU* p, DataType x)
{
  assert(p);
  Node* newnode = CreateNode(x);
  if (p->phead == NULL)//队列为空
  {
    p->phead = p->ptail = newnode;
  }
  else//队列不为空
  {
    p->ptail->next = newnode;
    p->ptail = newnode;
  }
  ++p->size;
}
//队列判空 
bool QueueEmpty(QU* p)
{
  assert(p);
  return p->phead == NULL;
}
//出队列,队头 
void QueuePop(QU* p)
{
  assert(p);
  assert(!QueueEmpty(p));//队列为空不能出队
  if (p->phead == p->ptail)//只有一个元素时
  {
    free(p->phead);
    p->phead = p->ptail = NULL;
  }
  else
  {
    Node* del = p->phead;
    p->phead = p->phead->next;
    free(del);
  }
  --p->size;
}
//取队头数据 
DataType QueueFront(QU* p)
{
  assert(p);
  assert(!QueueEmpty(p));//队列不能为空
  return p->phead->data;
}
//取队尾数据 
DataType QueueBack(QU* p)
{
  assert(p);
  assert(!QueueEmpty(p));//队列不能为空
  return p->ptail->data;
}
//队列长度
int QueueSize(QU* p)
{
  assert(p);
  return p->size;
}
//销毁队列 
void QueueDestroy(QU* p)
{
  assert(p);
  assert(!QueueEmpty(p));//队列不能为空
  Node* pcur = p->phead;
  while (pcur)
  {
    Node* next = pcur->next;
    free(pcur);
    pcur = next;
  }
  p->phead = p->ptail = NULL;
  p->size = 0;
}

main.c

#define _CRT_SECURE_NO_WARNINGS
#include"Queue.h"
void test()
{
  QU qu;
  QueueInit(&qu);
  QueuePush(&qu, 1);
  QueuePush(&qu, 2);
  QueuePush(&qu, 3);
  QueuePush(&qu, 4);
  QueuePop(&qu);
  printf("head:%d\n", QueueFront(&qu));
  printf("back:%d\n", QueueBack(&qu));
  printf("size:%d\n", QueueSize(&qu));
}
int main()
{
  test();
  return 0;
}

五、总结

  1. 初始化队列:创建一个空队列,准备进行后续操作。
  2. 入队:实现了在队尾添加新元素的功能,确保队列能够动态扩展。
  3. 队列判空:提供了检查队列是否为空的方法,便于在操作前判断队列状态。
  4. 出队:实现了从队首移除元素的功能,遵循先进先出的原则。
  5. 取队首元素:能够访问当前队首元素,但不移除它,方便查看下一个处理的元素。
  6. 取队尾元素:允许访问队尾元素,虽然不常见,但在某些场景中有其用途。
  7. 获取队列长度:实现了获取当前队列中元素数量的功能,便于管理和监控队列状态。
  8. 销毁队列:提供了清理队列资源的方法,防止内存泄漏。

通过实现这些基本操作,我们展示了队列的基本特性和使用方法,为理解队列在实际应用中的重要性奠定了基础。队列作为一种重要的数据结构,在任务调度、资源管理等多个领域都有广泛应用。希望这篇博客能帮助你更好地理解和使用队列。

 


相关文章
|
6月前
|
算法 前端开发 vr&ar
☆打卡算法☆LeetCode 225. 用队列实现栈 算法解析
☆打卡算法☆LeetCode 225. 用队列实现栈 算法解析
【栈和队列面试题】用栈实现队列(动图解析更清晰)
【栈和队列面试题】用栈实现队列(动图解析更清晰)
|
6月前
|
存储 缓存 算法
Python中collections模块的deque双端队列:深入解析与应用
在Python的`collections`模块中,`deque`(双端队列)是一个线程安全、快速添加和删除元素的双端队列数据类型。它支持从队列的两端添加和弹出元素,提供了比列表更高的效率,特别是在处理大型数据集时。本文将详细解析`deque`的原理、使用方法以及它在各种场景中的应用。
|
5月前
|
安全 Java 调度
Java Queue深度解析:LinkedList为何成为队列的最佳实践?
【6月更文挑战第18天】Java的`LinkedList`适合作为队列,因其双向链表结构支持O(1)的头尾操作。非线程安全的`LinkedList`在单线程环境下效率高,多线程时可通过`Collections.synchronizedList`封装。此外,它还可兼做栈和双端队列,提供任务调度的高效解决方案。
63 3
|
5月前
|
消息中间件 存储 NoSQL
Celery:高效异步任务队列的深度解析与应用实践
Celery 是一个流行的 Python 分布式任务队列,用于处理耗时的异步任务,提升Web应用性能。它包括消息中间件(如RabbitMQ、Redis)、任务生产者和消费者。Celery支持异步处理、分布式执行、任务调度、结果存储和错误处理。通过一个发送邮件验证码的实例,展示了如何安装配置、定义任务、触发任务以及查看执行结果。Celery的使用能有效优化应用响应速度和资源管理。
876 3
|
6月前
|
消息中间件 存储 监控
解析RocketMQ:高性能分布式消息队列的原理与应用
RocketMQ是阿里开源的高性能分布式消息队列,具备低延迟、高吞吐和高可靠性,广泛应用于电商、金融等领域。其核心概念包括Topic、Producer、Consumer、Message和Name Server/Broker。RocketMQ支持异步通信、系统解耦、异步处理和流量削峰。关键特性有分布式架构、顺序消息、高可用性设计和消息事务。提供发布/订阅和点对点模型,以及消息过滤功能。通过集群模式、存储方式、发送和消费方式的选择进行性能优化。RocketMQ易于部署,可与Spring集成,并与Kafka等系统对比各有优势,拥有丰富的生态系统。
802 4
|
6月前
|
存储 Java C++
Java集合篇之深度解析Queue,单端队列、双端队列、优先级队列、阻塞队列
Java集合篇之深度解析Queue,单端队列、双端队列、优先级队列、阻塞队列
55 0
|
6月前
|
安全 算法 调度
C++队列探秘:队列容器的使用技巧与实战案例解析
C++队列探秘:队列容器的使用技巧与实战案例解析
217 0
|
Java 容器
Java 并发编程:解析多种队列类型的用途 Queue Nice !!!
Java 并发编程:解析多种队列类型的用途 Queue Nice !!!
54 0
|
消息中间件 存储 Apache
深入探索分布式消息队列:Apache RocketMQ 介绍与特性解析
在现代的分布式系统中,消息队列已经成为了实现异步通信、解耦和扩展性的重要工具。Apache RocketMQ,作为一款高性能、可靠的分布式消息队列系统,正受到越来越多企业和开发者的关注和采用。本文将为您详细介绍 Apache RocketMQ 的核心概念、特性以及它在分布式架构中的应用。
324 0

推荐镜像

更多