数据结构——队列

目录

1>>导言

2>>队列的结构

3>>初始化

4>>打印

5>>入列

6>>出列

6.1>>判断是否为空

7>>取队头和队尾数据and统计个数

8>>队列销毁

9>>三个文件代码

queue.h

queue.c

test.c

10>>总结


1>>导言

在把栈学习完后,步入新的章节------队列,队列是一种特殊的线性表,队列是啥意思呢?栈表示先进后出,入栈出栈操作,类似一个水杯从上边喝水,那么队列是一个先进先出,入列出列的操作,类似生活中的排队,也类似被司马光砸破的水缸,先进来的水总是先出去,这便是队列。在表的后端进行插入操作。进行插入操作的端称为‌队尾 **,进行删除操作的端称为‌队头。**到这同学们应该是听懂了一部分,那么队列的底层结构用什么更为合适呢?我们一起来看看,假设用数组,那很显然,总会存在一个时间复杂度为O(N)的(自己写的函数),因为毕竟是有n个数。

比如这里,1号是队头,先进先出,排队出去。底层结构就用单链表来实现更简单,入列就是尾插,出列就是头删,取头结点元素。这里请大家思考:单链表就一个头结点,尾插到第n个数据,那么时间复杂度为O(N),有什么办法将它降为O(1)吗?在结构中给出答案:

因此我们就来看看队列的结构

2>>队列的结构

注意这里还是和之前的一样包含3个文件,包括:queueI(队列头文件、queuel、(队列尾部文件,test(测试文件)

队列的结构如下

data跟之前一样,在更改数据类型时可以统一修改,它的结构也是跟单链表无太大差异,唯一有所不同的是:我们要再写一个结构体,这个结构体用来存放头结点和尾结点。还有数据个数,这样可以使得时间复杂度降为O(1);

虽然我们多写了一个结构体,但是让时间复杂度从O(N)降为了O(1),因此在导言中给出的思考就解决了。

接下来根据下面图片的每一个声明做出相应的解释。

3>>初始化

初始化的时候,当然进来要先判断pq是否是空指针。需要把结构体内部的phead和ptail,头结点和尾结点置为空指针,并且让表示结点(人头数)个数的size置为0;在test文件创建完q并返回q的地址,进行初始化。

4>>打印

打印的代码也是一样,进来需要先判断pq是否是空指针,然后建立一个结构体指针,pcur,pcur为pq指向的下一个地址,

在这张图中也就是2;最后当pcur为空指针时,跳出循环。

5>>入列

入列进来也需要判断是否时空指针,为空则pq为假,NULL是0,assert进行断言报错,不为空则进入入列代码,首先:创建一个新结点,新节点类型为结构体指针,这里都跟单链表尾插是一样的,然后使用malloc开辟一个空间,大小为结构体指针的大小。当内存满时,会返回一个空指针,因此我们需要进行判断,为空则打印错误信息并退出,不为空则对新节点初始化------next置为空,val=x;至此为止,新节点创建完毕。

开始进行尾插,也就是入列

这里需要判断是否是第一个结点,如果是,则直接将头和尾直接置为第一个结点的地址,如果不是,则将尾结点的下一个地址改为新节点也就是newnode,然后原来的尾结点更新为新的尾结点。

最后将结点(人头数)加1即可。

6>>出列

在出列的代码里,assert还需要判断是否有结点可以删除,否则会对空指针解引用

6.1>>判断是否为空

所以这里就需要再写一个判断是否为空,如果头结点是空指针就为空,返回true。

那么出列代码的assert要对结果取反,不为空的时候返回false,然后取反为true,这样才能继续执行下面的代码。这里也需要判断一个结点和多个结点的情况,一个结点时,需要把头结点和尾结点置为空指针,因为就他一个能删除,多个结点时,提前存储下一个结点的地址 ,在对pq指向的phead进行释放,然后phead等于下一个结点地址即可完成出列。最后别忘了将结点成员数减一。

7>>取队头和队尾数据and统计个数

这三个比较简单,就放在一起啦,宝子们一起看看就好。

8>>队列销毁

最后是队列的一个销毁,还是和打印差不多,都需要提前存好下一个结点的地址,然后一个一个的释放,最后将头结点和尾结点都置为空指针,然后将size置为0.

9>>三个文件代码

queue.h

cpp 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
#include<stdbool.h>

typedef int data;

typedef struct queuenode {
	data val;
	struct queuenode* next;
}queuenode;

typedef struct queue {
	queuenode* phead;
	queuenode* ptail;
	int size;
}queue;

void qinit(queue*pq);//初始化

void qpirnt(queue* pq);//打印

void qpush(queue* pq, data x);//入列
void qpop(queue* pq);//出列

data qfront(queue* pq);//取队头数据
data qback(queue* pq);//取队尾数据

bool qempty(queue* pq);//判断队列是否为空
int qsize(queue* pq);//统计队列个数

void qdestroy(queue* pq);//队列的销毁

queue.c

cpp 复制代码
#include"queue.h"

void qinit(queue* pq) {
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

void qpirnt(queue* pq) {
	assert(pq);
	queuenode* pcur;
	pcur = pq->phead;
	while (pcur) {
		printf("%d -> ", pcur->val);
		pcur = pcur->next;
	}
	printf("\n");
}
void qpush(queue* pq,data x) {
	assert(pq);
	queuenode* newnode = (queuenode*)malloc(sizeof(queuenode));
	if (newnode == NULL) {
		perror("malloc");
		exit(1);
	}
	newnode->next = NULL;
	newnode->val = x;
	if (pq->phead == NULL) {
		pq->phead = pq->ptail = newnode;
	}
	else {
		pq->ptail->next=newnode;
		pq->ptail = pq->ptail->next;
	}
	pq->size++;
}

void qpop(queue* pq) {
	assert(pq);
	assert(!qempty(pq));
	if (pq->phead==pq->ptail)
		pq->phead = pq->ptail = NULL;
	else
	{
		queuenode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	pq->size--;
}
data qfront(queue* pq) {
	assert(pq);
	assert(!qempty(pq));
	return pq->phead->val;
}
data qback(queue* pq) {
	assert(pq);
	assert(!qempty(pq));
	return pq->ptail->val;
}
bool qempty(queue* pq) {
	assert(pq);
	return pq->phead == NULL;
}

int qsize(queue* pq) {
	assert(pq);
	return pq->size;
}

void qdestroy(queue* pq) {
	assert(pq);
	queuenode* pcur = pq->phead;
	while (pcur) {
		queuenode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

test.c

cpp 复制代码
#include"queue.h"

void test() {
	queue q;
	qinit(&q);
	qpush(&q,1);
	qpush(&q, 2);
	qpush(&q, 3);
	qpush(&q, 4);
	qpirnt(&q);
	printf("%d\n", qsize(&q));
	qpop(&q);
	printf("%d\n", qsize(&q));

}
int main() {
	
	test();
	return 0;
}

10>>总结

今天带着宝子们学习了队列的知识点,包括入列,出列等等队列的操作,希望宝子们在这篇文章能学会使用队列,也希望宝子们数据结构越学越好,无瓶颈!谢谢宝子们观看,期待下一篇与你相见!

相关推荐
IronmanJay1 小时前
【LeetCode每日一题】——862.和至少为 K 的最短子数组
数据结构·算法·leetcode·前缀和·双端队列·1024程序员节·和至少为 k 的最短子数组
喵手1 小时前
Java 与 Oracle 数据泵实操:数据导入导出的全方位指南
java·开发语言·oracle
硬汉嵌入式2 小时前
H7-TOOL的LUA小程序教程第16期:脉冲测量,4路PWM,多路GPIO和波形打印(2024-10-25, 更新完毕)
开发语言·junit·小程序·lua
Wx120不知道取啥名2 小时前
C语言之长整型有符号数与短整型有符号数转换
c语言·开发语言·单片机·mcu·算法·1024程序员节
Python私教3 小时前
Flutter颜色和主题
开发语言·javascript·flutter
代码吐槽菌3 小时前
基于SSM的汽车客运站管理系统【附源码】
java·开发语言·数据库·spring boot·后端·汽车
Ws_3 小时前
蓝桥杯 python day01 第一题
开发语言·python·蓝桥杯
zdkdchao3 小时前
jdk,openjdk,oraclejdk
java·开发语言
神雕大侠mu4 小时前
函数式接口与回调函数实践
开发语言·python
IT规划师4 小时前
数据结构 - 散列表,三探之代码实现
数据结构·散列表·哈希表