数据结构——队列

目录

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>>总结

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

相关推荐
Fanxt_Ja2 天前
【LeetCode】算法详解#15 ---环形链表II
数据结构·算法·leetcode·链表
侃侃_天下2 天前
最终的信号类
开发语言·c++·算法
echoarts2 天前
Rayon Rust中的数据并行库入门教程
开发语言·其他·算法·rust
Aomnitrix2 天前
知识管理新范式——cpolar+Wiki.js打造企业级分布式知识库
开发语言·javascript·分布式
每天回答3个问题2 天前
UE5C++编译遇到MSB3073
开发语言·c++·ue5
今后1232 天前
【数据结构】二叉树的概念
数据结构·二叉树
伍哥的传说2 天前
Vite Plugin PWA – 零配置构建现代渐进式Web应用
开发语言·前端·javascript·web app·pwa·service worker·workbox
小莞尔2 天前
【51单片机】【protues仿真】 基于51单片机八路抢答器系统
c语言·开发语言·单片机·嵌入式硬件·51单片机
我是菜鸟0713号2 天前
Qt 中 OPC UA 通讯实战
开发语言·qt
JCBP_2 天前
QT(4)
开发语言·汇编·c++·qt·算法