首页 > 其他分享 >数据结构——队列

数据结构——队列

时间:2024-10-21 17:19:30浏览次数:3  
标签:assert 结点 pq 队列 queue phead 数据结构

目录

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

#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

#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

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

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

标签:assert,结点,pq,队列,queue,phead,数据结构
From: https://blog.csdn.net/m0_69282950/article/details/143114934

相关文章

  • Java消息队列详解
    消息队列的作用及原理消息队列产生主要是为了解决系统间的异步解耦与确保数据最终一致性问题。通过将主流程与辅助流程分离,使得辅助任务可以并行处理,不仅提高了系统的响应速度,还增强了其可扩展性和稳定性。此外,消息队列机制保证了每条消息至少被消费一次,从而确保了业务逻辑的......
  • 【数据结构】动态规划:揭开算法优化的秘密
    在算法世界中,动态规划(DynamicProgramming,DP)无疑是一个充满魅力的思想,特别是在解决复杂的优化问题时,它展现出了极大的威力。它不仅能优化问题的求解速度,还能通过减少重复计算来提高效率。然而,对于很多初学者来说,动态规划常常显得有些晦涩难懂。本文将通过浅显的例子,帮助你......
  • 新高一暑假第一期集训恢复性训练【数据结构-并查集】(补)
    新高一暑假第一期集训恢复性训练【数据结构-并查集】(补)C.[POJ1417]TrueLiars先将题目中的好人和坏人转换一下,也即是如果\(x\)说\(y\)是好人,则他们两属于同一组,反之则不属于同一组。然后我们可以想到带权的并查集,用\(val_x\)代表\(x\)与其父节点的关系,当\(val_x\)......
  • Java语言快速实现简单MQ消息队列服务
    目录MQ基础回顾主要角色自定义协议流程顺序项目构建流程具体使用流程代码演示消息处理中心Broker消息处理中心服务BrokerServer客户端MqClient测试MQ小结 MQ基础回顾在上一篇消息通讯之关于消息队列MQ必须了解的相关概念中,我们尽可能地详细的了解......
  • 数据结构_day5(完结)
    目录7.树7.1特性7.1.1什么是树7.1.2关于树的一些术语7.2二叉树7.2.1什么是二叉树7.2.2二叉树性质(重点)7.2.3满二叉树和完全二叉树7.2.4二叉树的存储结构7.3二叉树的链式存储7.4层次遍历哈夫曼树Huffman图1.什么是图2.图的基本概念3.图的分类3.1......
  • 【趣学C语言和数据结构100例】
    【趣学C语言和数据结构100例】问题描述51.在一个递增有序的单链表中,存在重复的元素。设计算法删除重复的元素,例如(7.10.10.21.30.42.42.42.51.70)将变为(7.10.21.30.42.51.70)。52.设A和B是两个单链表(带头结点),其中元素递增有序。设计一个算法从A和B中的公共元素产......
  • 408数据结构-折半查找,分块查找 自学知识点整理
    前置知识:查找的基本概念折半查找折半查找又称二分查找,它仅适用于有序的顺序表。因个人习惯,下文均用二分代替折半。二分查找的基本思想:首先将给定值ke......
  • 【数据结构】队列
    ......
  • c#数据结构06_队列
    说明(此系列帖子记录数据结构学习成果,如侵犯视频作者权益,立删)视频链接:离忧夏天C#数据结构本文实现队列需要用到动态数组ArrayList和单链表的相关知识,详细请看:C#数据结构专栏文章目录一:队列的基本概念二:队列的基本操作三:队列的实现1.数组队列(由动态数组实现)2.循环......
  • 数据结构与算法
    数据结构:研究数据在内存中存储的结构算法:实现增删改查的方法解决问题的实际方法算法的好坏评价标准:时间复杂度和空间复杂度时间复杂度:算法所用时间的一个映射时间复杂度得出的是一个数学问题数据总量x(x足够大),从而消耗的执行次数y之间存在的关系LeetCode算法题......