Day5:数据结构之队列
Posted 雨轩(小宇)
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day5:数据结构之队列相关的知识,希望对你有一定的参考价值。
队列
目录 | 目录 |
---|---|
顺序表 | 单链表(不带附加头结点) |
双链表(带附加头结点) | 栈(顺序表实现) |
队列(链式,不带附加头结点) |
前言
这一节我们来学习队列,以及队列和栈的区别。
1、队列的概念
- 队列是另一种限定存取位置的线性表,只允许在队尾(rear)插入,队头(front)删除。(可以理解为排队打饭)
2、队列的实现方式
- 队列可以用数组和链表来实现,但相对于队列链表更优,链表实现头删和尾插不需要移动元素,数组是需要移动元素的,效率比较低。
3、队列的基本操作
头文件
#pragma once // 防止头文件重复包含
#include<stdio.h>
#include<assert.h> // 断言检查
#include<stdlib.h> // 动态内存函数头文件
#include<stdbool.h> // bool头文件
typedef int QDataType; // 给int重命名为QDataType
// 链式结构:表示队列
typedef struct QListNode
{
struct QListNode* next; // 指针域
QDataType data; // 数据域
}QNode;
// 队列的结构
typedef struct Queue
{
QNode* front; // 结构体队头指针
QNode* rear; // 结构体队尾指针
}Queue;
1. 初始化队列
- front 和 rear都等于NULL,表示空队列,即初始化队列
void QueueInit(Queue* q)
{
assert(q);
q->front = q->rear = NULL;
}
2. 队尾入队列
分两种情况判断
- 队列为空,新结点就插入在队头和队尾上
- 队列不为空,新结点直接插入在原队尾成为新的队尾
void QueuePush(Queue* q, QDataType data)
{
assert(q);
QNode* newnode = (QNode*)malloc(sizeof(QNode));// 创建新结点
if (newnode == NULL) // 检查是否开辟成功
{
perror("Push"); // 报错信息
exit(-1);
}
newnode->data = data; // 给新结点赋值
newnode->next = NULL; // 新结点变队尾,其指针域置空
if (q->rear == NULL)// 队列为空的时候
{
q->front = q->rear = newnode; // 队头和队尾都等于新结点
}
else
{
q->rear->next = newnode; // 原队尾指向新队尾(新结点)
q->rear = newnode; // 新结点变为队尾结点
}
}
3. 队头出队列
分两种情况判断
- 队列只有一个结点的时候,直接将队头删除,然后 front 和 rear 置空
- 队列多个结点的时候,需要先重命名第二个结点,然后再去删除队头
void QueuePop(Queue* q)
{
assert(q); // 断言检查
assert(!QueueEmpty(q)); // 检查是否非空,有元素才可以删除
if (q->front->next == NULL) // 只有一个结点时
{
free(q->front); // 释放,防止内存泄漏
q->front = q->rear = NULL; // 队头队尾置空
}
else
{
QNode* next = q->front->next; // 重命名第二个结点
free(q->front); // 释放,防止内存泄漏
q->front = next; // 让第二个结点成为队头
}
}
4. 获取队列头部元素
- 先检查是否非空,在获取队头元素即可
QDataType QueueFront(Queue* q)
{
assert(q);
assert(!QueueEmpty(q)); // 检查是否非空
return q->front->data; // 返回队头元素
}
5. 获取队列队尾元素
- 先检查是否非空,在获取队尾元素即可
QDataType QueueBack(Queue* q)
{
assert(q);
assert(!QueueEmpty(q)); // 检查是否非空
return q->rear->data; // 返回队尾元素
}
6. 获取队列有效个数
- 定义队头元素,迭代进行遍历即可
int QueueSize(Queue* q)
{
assert(q); // 断言检查
int len = 0;
QNode* cur = q->front; // 队头元素重命名
while (cur)
{
len++;
cur = cur->next; // 迭代
}
return len; // 返回个数
}
7. 判断队列为空
- 检测队列是否为空,如果为空返回非零,非空返回0
int QueueEmpty(Queue* q)
{
assert(q); // 断言检查
return q->front == NULL && q->rear == NULL;
// front和rear都为空,队列才空
}
8. 销毁队列
- 队头元素重命名,迭代一层一层删除即可
void QueueDestroy(Queue* q)
{
assert(q);
QNode* cur = q->front; // 队头元素重命名
while (cur)
{
QNode* next = cur->next; // 下一个结点,进行迭代
free(cur); // 释放内存,防止内存泄漏
cur = next; // 迭代
}
q->front = q->rear = NULL; // 释放完队头和队尾需要置空
}
4、队列面试题(结合栈)
学了队列,结合队列和栈,可以做一下下面的面试题来加深自己的理解
5、队列和栈的区别
- 队列先进先出,栈后进先出
- 队列是在两端队尾插入,队头删除,而栈只能在一端(栈顶)插入和删除
源码地址:队列源码
ps:制作不易,记得三连
以上是关于Day5:数据结构之队列的主要内容,如果未能解决你的问题,请参考以下文章