【数据结构初阶】队列的实现

⭐博客主页:️CS semi主页
⭐欢迎关注:点赞收藏+留言
⭐系列专栏:数据结构初阶
⭐代码仓库:Data Structure
家人们更新不易,你们的点赞和关注对我而言十分重要,友友们麻烦多多点赞+关注,你们的支持是我创作最大的动力,欢迎友友们私信提问,家人们不要忘记点赞收藏+关注哦!!!

队列的实现

  • 队列
    • 1、三板斧
    • 2、队列的概念及结构
    • 3、队列的实现
      • (1)链表队列
      • (2)初始化队列
      • (3)进队列
      • (4)出队列
      • (5)计算长度
      • (6)判断是否为空
      • (7)取队头
      • (8)取队尾
      • (9)测试
    • 4、源代码
  • 总结


队列

1、三板斧

【数据结构初阶】队列的实现_第1张图片

2、队列的概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头。
【数据结构初阶】队列的实现_第2张图片
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

3、队列的实现

(1)链表队列

我们定义的这个结构大家可能不是很理解,因为有一点点奇怪,这怎么定义两个结构体,定义Queue这个结构体的时候有两个指针还都是有数据和next的指针,那其实我们定义这两个结构体的原因是设立一个队头和一个队尾,我们不是简单地定义一个结构体前连后连的,而是定义的两个结点,一个是队头结点,一个是队尾结点,我们从上图可以看出来是有队尾和队头结点的。
【数据结构初阶】队列的实现_第3张图片

(2)初始化队列

初始化就将头结点尾结点置空,将size赋值为0即可。

//初始化
void QueueInit(Queue* pq) {
	assert(pq);
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

(3)进队列

我们先创建一个新的结点,如果此时队列里面什么数据都没有,那我们就将这个新结点为队头,如果此时队列中有节点,那就直接尾插即可。

【数据结构初阶】队列的实现_第4张图片


//进队列
void QueuePush(Queue* pq, QueueDataType x) {
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL) {
		perror("malloc failed");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;

	if (pq->head == NULL) {//链表内部啥也没有
		assert(pq->tail == NULL);
		pq->head = pq->tail = newnode;
	}
	else {
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
	pq->size++;
}

(4)出队列

出队列说白了就是头删,将数据从头删出去,然后将头结点往后移一位即可,我在下面写了两种写法,一种写法是先记录一下队头后面的结点,将队头数据free掉,再将队头往后更新,这其中还是有小细节的,当我们更新完以后发现这个队头结点是NULL,那也就是说没free之前是队头和队尾到一起了,那当队头更新以后将原本队头结点free掉以后,队尾是指向的是野指针了,太危险了,那就将队尾也置空即可,最后将size–也就是将队头结点出队列了;第二种写法比较体系化,将上面的思想放在if-else上,总体思路一样,但格式更加明朗。

常规情况:
【数据结构初阶】队列的实现_第5张图片

特殊情况
【数据结构初阶】队列的实现_第6张图片

//出队列
void QueuePop(Queue* pq) {
	assert(pq);
	assert(pq->head != NULL);
	/*QNode* cur = pq->head;
	QNode* next = cur->next;
	free(cur);
	pq->head = next;
	if (pq->head == NULL) {
		pq->tail = NULL;
	}
	pq->size--;*/

	if (pq->head->next == NULL) {
		free(pq->head);
		pq->tail = pq->head = NULL;
	}
	else {
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
	pq->size--;
}

(5)计算长度

这个和我们的栈有区别了,这个是size从0开始,不会导致多一个的情况,所以直接返回size即可。

//计算长度
int QueueSize(Queue* pq) {
	assert(pq);
	return pq->size;
}

(6)判断是否为空

利用bool值,判断头结点和尾结点是否同时为空即可。

//判断是否为空
bool QueueEmpty(Queue* pq) {
	assert(pq);
	return pq->head == NULL && pq->tail == NULL;
}

(7)取队头

当队列不为空的时候,我们直接输出队头的数据即可。

//取队头
QueueDataType QueueFront(Queue* pq) {
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->head->data;
}

(8)取队尾

和取队头一样,直接输出队尾的数据即可。

//队尾
QueueDataType QueueBack(Queue* pq) {
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->data;
}

(9)测试

int main() {
	Queue pq;
	QueueInit(&pq);
	QueuePush(&pq, 1);
	QueuePush(&pq, 2);
	QueuePush(&pq, 3);
	QueuePush(&pq, 4);
	QueuePush(&pq, 5);

	int j = QueueSize(&pq);
	printf("%d\n", j);
	
	//只能先进再出进的值,不能遍历
	while (!QueueEmpty(&pq)) {
		printf("%d ", QueueFront(&pq));
		QueuePop(&pq);
	}
	printf("\n");

	int i = QueueSize(&pq);
	printf("%d", i);

	QueueDestroy(&pq);
	return 0;
}

输出结果:

4、源代码

Queue.h:

//用链表实现
//先进先出
#include
#include
#include
#include
#include

typedef int QueueDataType;

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

typedef struct Queue {
	QNode* head;
	QNode* tail;
	QueueDataType size;
}Queue;

//初始化
void QueueInit(Queue* pq); //改变结构体成员就用结构体的指针即可

//销毁链表
void QueueDestroy(Queue* pq);

//进队列
void QueuePush(Queue* pq, QueueDataType x);

//出队列
void QueuePop(Queue* pq);

//计算长度
int QueueSize(Queue* pq);

//判断是否为空
bool QueueEmpty(Queue* pq);

//队头
QueueDataType QueueFront(Queue* pq);

//队尾
QueueDataType QueueBack(Queue* pq);

Queue.c:

#include"Queue.h"

//初始化
void QueueInit(Queue* pq) {
	assert(pq);
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

//销毁链表
void QueueDestroy(Queue* pq) {
	assert(pq);
	QNode* cur = pq->head;
	while (cur) {
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

//进队列
void QueuePush(Queue* pq, QueueDataType x) {
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL) {
		perror("malloc failed");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;

	if (pq->head == NULL) {//链表内部啥也没有
		assert(pq->tail == NULL);
		pq->head = pq->tail = newnode;
	}
	else {
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
	pq->size++;
}

//出队列
void QueuePop(Queue* pq) {
	assert(pq);
	assert(pq->head != NULL);
	/*QNode* cur = pq->head;
	QNode* next = cur->next;
	free(cur);
	pq->head = next;
	if (pq->head == NULL) {
		pq->tail = NULL;
	}
	pq->size--;*/

	if (pq->head->next == NULL) {
		free(pq->head);
		pq->tail = pq->head = NULL;
	}
	else {
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
	pq->size--;
}

//计算长度
int QueueSize(Queue* pq) {
	assert(pq);
	return pq->size;
}

//判断是否为空
bool QueueEmpty(Queue* pq) {
	assert(pq);
	return pq->head == NULL && pq->tail == NULL;
}

//取队头
QueueDataType QueueFront(Queue* pq) {
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->head->data;
}

//队尾
QueueDataType QueueBack(Queue* pq) {
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->data;
}

Test.c:

#include"Queue.h"

int main() {
	Queue pq;
	QueueInit(&pq);
	QueuePush(&pq, 1);
	QueuePush(&pq, 2);
	QueuePush(&pq, 3);
	QueuePush(&pq, 4);
	QueuePush(&pq, 5);

	int j = QueueSize(&pq);
	printf("%d\n", j);
	
	//只能先进再出进的值,不能遍历
	while (!QueueEmpty(&pq)) {
		printf("%d ", QueueFront(&pq));
		QueuePop(&pq);
	}
	printf("\n");

	int i = QueueSize(&pq);
	printf("%d", i);

	QueueDestroy(&pq);
	return 0;
}

总结

队列的实现同样也是学习数据结构初期比较基础的结构,掌握这个结构对后续的数据结构学习有很大的帮助。

家人们不要忘记点赞收藏+关注哦!!!

你可能感兴趣的:(数据结构初阶,数据结构,链表,算法,c语言)