Day5:数据结构之队列

Posted 雨轩(小宇)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day5:数据结构之队列相关的知识,希望对你有一定的参考价值。

目录目录
顺序表单链表(不带附加头结点)
双链表(带附加头结点)栈(顺序表实现)
队列(链式,不带附加头结点)

前言

这一节我们来学习队列,以及队列和栈的区别。

1、队列的概念

  1. 队列是另一种限定存取位置的线性表,只允许在队尾(rear)插入,队头(front)删除。(可以理解为排队打饭)

2、队列的实现方式

  1. 队列可以用数组和链表来实现,但相对于队列链表更优,链表实现头删和尾插不需要移动元素,数组是需要移动元素的,效率比较低。

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. 初始化队列

  1. front 和 rear都等于NULL,表示空队列,即初始化队列
void QueueInit(Queue* q)
{
	assert(q);
	q->front = q->rear = NULL;
}

2. 队尾入队列

分两种情况判断

  1. 队列为空,新结点就插入在队头和队尾上
  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. 队头出队列

分两种情况判断

  1. 队列只有一个结点的时候,直接将队头删除,然后 front 和 rear 置空
  2. 队列多个结点的时候,需要先重命名第二个结点,然后再去删除队头

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. 获取队列头部元素

  1. 先检查是否非空,在获取队头元素即可
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q)); // 检查是否非空
	return q->front->data; // 返回队头元素
}

5. 获取队列队尾元素

  1. 先检查是否非空,在获取队尾元素即可
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q)); // 检查是否非空
	return q->rear->data; // 返回队尾元素
}

6. 获取队列有效个数

  1. 定义队头元素,迭代进行遍历即可
int QueueSize(Queue* q)
{
	assert(q); // 断言检查
	int len = 0;
	QNode* cur = q->front; // 队头元素重命名
	while (cur)
	{
		len++;
		cur = cur->next; // 迭代
	}
	return len; // 返回个数
}

7. 判断队列为空

  1. 检测队列是否为空,如果为空返回非零,非空返回0
int QueueEmpty(Queue* q)
{
	assert(q); // 断言检查
	return q->front == NULL && q->rear == NULL; 
	// front和rear都为空,队列才空
}

8. 销毁队列

  1. 队头元素重命名,迭代一层一层删除即可
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、队列面试题(结合栈)

学了队列,结合队列和栈,可以做一下下面的面试题来加深自己的理解

  1. 设计循环队列
  2. 用队列实现栈
  3. 用栈设计队列

5、队列和栈的区别

  1. 队列先进先出,栈后进先出
  2. 队列是在两端队尾插入,队头删除,而栈只能在一端(栈顶)插入和删除

源码地址:队列源码

ps:制作不易,记得三连

以上是关于Day5:数据结构之队列的主要内容,如果未能解决你的问题,请参考以下文章

# Java 常用代码片段

# Java 常用代码片段

java之day5

学习windows编程 day5 之 区域裁剪

Day5:Python学习笔记之Linux——用户和权限

day5-python之递归与二分法