【数据结构初阶】队列(单链表实现)

队列的概念以及结构

队列:只允许在队头进行删除数据操作,队尾进行插入数据操作,队列具有先进先出的特点。

队列可以用数组实现也可以使用链表实现,下面展示的是通过单链表实现的

队列结构.jpg

很明显,我们可以看到,只有队头和队尾两个结点可以被直接访问

👀接着我们来看看队列的定义

首先是结点,这与单链表的结点结构一致

typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;

接着是队列的结构,对应着上面的图片,这个队列的结构相当于就是蓝色的框架以及两个指向队首结点、队尾结点的指针

typedef struct Queue
{
	QueueNode* head;
	QueueNode* rear;
}Queue;

主要操作

入队

队列入队.jpg

入队的操作与单链表的尾插一致,并且因为尾指针的存在,入队的时间复杂度为O(1)

⭐️这里要注意若队列中有元素时,新结点是插在队尾结点的后面;而队列为空时,只需要直接将新结点直接赋给队首指针和队尾指针即可

void QueuePush(Queue* q, QDataType data)
{
	assert(q);
	QNode* newNode = (QNode*)malloc(sizeof(QNode));
	if (newNode == NULL)//检查新结点空间是否申请成功
		printf("malloc fail.");
	newNode->data = data;
	newNode->next = NULL;

	if (q->rear == NULL)
	{
		q->head = q->rear = newNode;
	}
	else
	{
		q->rear->next = newNode;
		q->rear = newNode;
	}
}

出队

队列出队.jpg

我们先用一个指针指向当前的队首结点

接着队首指针指向下一个结点

最后将出队的队首结点释放即可

⭐️这时候我们也需要注意,当队列为空的时候是无法进行出队操作的

以及队中仅有一个元素的时候,队首指针是不用进行后移操作的

void QueuePop(Queue* q)
{
	assert(q);
	assert(q->head && q->rear);	//避免队列中无元素的时候进行出队操作
    /*
    当然这里也可以选择比较柔和的检查方式,例如用if条件语句进行判断
    */
	QNode* qf = q->head;		//先用一个指针拿到队头结点

	if (qf->next == NULL)
	{//队中只有一个元素的时候
		free(qf);
		q->head = q->rear = NULL;
	}
	else
	{//队中有多个元素的时候
		q->head = q->head->next;//队首指针后移
		free(qf);
	}

}

还有一些操作例如获取队首、队尾元素,获取队列有效元素个数等,就放在下面的整体代码啦

整体代码

头文件:

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

typedef int QDataType;

typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;

typedef struct Queue
{
	QueueNode* head;
	QueueNode* rear;
}Queue;

// 初始化队列
void QueueInit(Queue* q);

// 队尾入队列
void QueuePush(Queue* q, QDataType data);

// 队头出队列
void QueuePop(Queue* q);

// 获取队列头部元素
QDataType QueueFront(Queue* q);

// 获取队列队尾元素
QDataType QueueBack(Queue* q);

// 获取队列中有效元素个数
size_t QueueSize(Queue* q);

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* q);

// 销毁队列
void QueueDestroy(Queue* q);

函数实现:


#include "queue.h"

// 初始化队列
void QueueInit(Queue* q)
{
	assert(q);
	q->head = q->rear = NULL;
}

// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{
	assert(q);
	QNode* newNode = (QNode*)malloc(sizeof(QNode));
	if (newNode == NULL)//检查新结点空间是否申请成功
		printf("malloc fail.");
	newNode->data = data;
	newNode->next = NULL;

	if (q->rear == NULL)
	{
		q->head = q->rear = newNode;
	}
	else
	{
		q->rear->next = newNode;
		q->rear = newNode;
	}
}

// 队头出队列
void QueuePop(Queue* q)
{
	assert(q);
	assert(q->head && q->rear);	//避免队列中无元素的时候进行出队操作
	QNode* qf = q->head;		//先用一个指针拿到队头结点

	if (qf->next == NULL)
	{//队中只有一个元素的时候
		free(qf);
		q->head = q->rear = NULL;
	}
	else
	{//队中有多个元素的时候
		q->head = q->head->next;//队首指针后移
		free(qf);
	}

}

// 获取队列头部元素
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(q->head);
	/*当然这里也可以使用温柔点的检查
		if (q->head == NULL)
			printf("Queue is empty.");
	*/
	return q->head->data;
}

// 获取队列队尾元素
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->rear);
	return q->rear->data;
}

// 获取队列中有效元素个数
size_t QueueSize(Queue* q)
{
	assert(q);
	QNode* cur = q->head;
	size_t size = 0;
	while (cur)
	{
		size++;
		cur = cur->next;
	}
	return size;
}

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* q)
{
	assert(q);
	return q->head == NULL;
}

// 销毁队列
void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* cur = q->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	q->head = q->head = NULL;
}

例牌小测试:

1648302728_1_.png

😄我是旺仔,和你一起成长

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值