数据结构——队列

目录

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

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

相关推荐
计算机相关知识分享3 分钟前
python基础知识(二)
开发语言·python
Python私教32 分钟前
PyPika:Python SQL 查询构建器
开发语言·python·sql
全栈老实人_34 分钟前
考研互学互助系统|Java|SSM|VUE| 前后端分离
java·开发语言·tomcat·maven
天天进步201538 分钟前
Java全栈项目实战:校园报修服务系统
java·开发语言
Gpluso_od1 小时前
算法常用库函数——C++篇
数据结构·c++·算法
Themberfue1 小时前
Java 网络原理 ①-IO多路复用 || 自定义协议 || XML || JSON
xml·java·开发语言·网络·计算机网络·json
m0_699659561 小时前
DAY3 QT简易登陆界面优化
开发语言·qt·命令模式
bingw01141 小时前
25. 求满足条件的最长子串的长度
数据结构·算法
励志成为大佬的小杨2 小时前
关键字初级学习
c语言·开发语言·算法
szpc16213 小时前
100V宽压输入反激隔离电源,适用于N道沟MOSFET或GaN或5V栅极驱动器,无需光耦合
c语言·开发语言·人工智能·单片机·嵌入式硬件·生成对抗网络·fpga开发