栈和队列(2)

编程入门 行业动态 更新时间:2024-10-07 22:27:22

栈和<a href=https://www.elefans.com/category/jswz/34/1771257.html style=队列(2)"/>

栈和队列(2)

目录

🍁一、链表的概念

🍁二、针对本文章给出的几点注意事项:

🍁三、队列的实现

🌕(一)、代码定义

注意:

🌕(二)、初始化

🌕(三)、入队

🌕(四)、出队

🌕(五)、取队头元素

🌕(六)、取队尾元素

🌕(七)、判空

🌕(八)、获取队列元素个数

🌕(九)、销毁

🌕(十)、遍历

🍁、队列实现源代码

🌕(一)、main.c

🌕(二)、Queue.c

🌕(三)、Queue.h


🍁一、链表的概念

①:队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表。 ②:队列具有 先进先出(简称FIFO (First In First Out))的特点 ③:入队列:进行插入操作的一端称为 队尾        出队列:进行删除操作的一端称为 队头 ④:常见使用场景:

🍁二、针对本文章给出的几点注意事项:

(一)、队列使用单向队列即可,因为双向体现不了它的优势,而且双向还会多一个指针域,内存能省一点是一点

(二)、哨兵位(带头)可要可不要,因为哨兵一般解决结构体二级指针,而本次小编会以另外一种方法解决二级指针的问题

(三)、队列可以用数组实现,也可以用链表来实现,但优先选择链表,对于队列,链表的优势远大于数组,因为数组入队很简单,但出队就涉及数据的覆盖,比较麻烦;

(四)、在链表的头部进行出队,尾部进行入队。

(五)、队列实现的具体步骤我会放在代码注释里面,大家请注意一下!因为小编找不到合适的方式,有推荐的小伙伴可以评论区给小编一些建议。

🍁三、队列的实现

🌕(一)、代码定义

之前实现链表的时候我们知道,在不带头且插入第一个数据时会修改结构体指针,此时就需要使用二级指针的参与,从而分类讨论,是情况变得复杂;既然我们不带头,并且这里即需要头指针还需要尾指针,那么我们可以有如下实现:

typedef int QDatatype;
typedef struct QueueNode
{struct QueueNode* next;QDatatype data;
}QNode;typedef struct Queue
{QNode* head;//头指针,指向首结点QNode* tail;//尾指针,指向为结点int size;//记录队列长度
}Que;

我们将头指针head和尾指针tail重新封装成一个结构体,这样即使是在插入第一个数据,那么我们修改head指针,相当于修改结构体Queue的成员,所以我们全部情况只需要结构体Queue的一级指针即可;

注意:

截至目前:我们已经接触了三种改变结构体指针head不需要传参数二级指针的方法:

(一)、就是使用带哨兵的head,这样改变的是head的next域,即改变结构体成员;

(二)、使用不带哨兵的head,但最后会返回新head,在函数外面用适当的指针来接收返回值;

(三)、就是上述所示,在不带哨兵的情况,将头指针、尾指针封装成一个结构体,这样改变head或tail时,改变的是该结构体的成员,只需使用该结构体的一级指针即可;

🌕(二)、初始化

//初始化
void Queueinit(Que* ps)
{assert(ps);ps->head = ps->tail = NULL;ps->size = 0;
}

🌕(三)、入队

①:因为我们使用的是链表结构,所以不用考虑增容;

②:但入队的时候要注意第一次入队时的区别,从而分类讨论;

③:入队后元素数量加1;

//入队
void QueuePush(Que* ps, QDatatype x)
{assert(ps);//创建一个新结点QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc");return;}//因为是在尾结点入队,所以入队之后结点next域要置空newnode->data = x;newnode->next = NULL;//第一次插入是结构体指针之间的赋值,之后才是结构体成员的赋值,所以要分情况//记住tail指针始终指向尾结点,所以入队之后要对tail指针重定位if (ps->tail == NULL){ps->head = ps->tail = newnode;}else{ps->tail->next = newnode;ps->tail = newnode;}//入队后元素数量+1ps->size++;
}

🌕(四)、出队

出队的时候也要注意几点事项:

①:出队前,一定要检查队列是否为空;

②:因为队列涉及头指针head和尾指针tail,所以当出队列的最后一个元素后,head和tail指针都要指向NULL,所以我们可以分类讨论以防万一;

③:出队后元素数量size减1

//出队
void QueuePop(Que* ps)
{assert(ps);//检查队列是否为空,若为空则assert函数报错提示assert(!QueueEmpty(ps));//队列不为空,进行尾删//当对列只剩下一个元素时,要注意head和tail指针都要指向NULL,所以为了安全起见,进行分类讨论if (ps->head->next == NULL){free(ps->head);//注意free释放的是该指针指向的空间,而不是释掉该指针ps->head = ps->tail = NULL;}else{QNode* next = ps->head->next;free(ps->head);ps->head = next;}//出队列,元素数量-1ps->size--;
}

🌕(五)、取队头元素

操作很简单,只需返回head结点的data域;

但要注意,首先要检查队列是否为空:

//取队头
QDatatype QueueFront(Que* ps)
{assert(ps);//检查队列为不为空assert(!QueueEmpty(ps));//返回首结点的data域return ps->head->data;
}

🌕(六)、取队尾元素

操作和(五)类似:

//取队尾
QDatatype QueueBack(Que* ps)
{assert(ps);//检查队列为不为空assert(!QueueEmpty(ps));//返回尾结点的data域return ps->tail->data;
}

🌕(七)、判空

规则:

队列为空返回真;

队列不为空返回假;

我们用一个表达式的逻辑值来实现,如下:

//判空
bool QueueEmpty(Que* ps)
{assert(ps);//为空返回真,不为空返回假return (ps->head == NULL);
}

🌕(八)、获取队列元素个数

操作很简单,直接返回size即可:


//获取队列元素个数
int QueueSize(Que* ps)
{assert(ps);return ps->size;
}

🌕(九)、销毁

与单链表的销毁类似,一个结点一个结点的销毁;

先用临时指针cur指向head,再用临时指针next保存cur的下一个结点,再释放当前结点cur,然后cur重定位到下一个结点,直至cur为NULL;

//销毁
void QueueDestroy(Que* ps)
{assert(ps);QNode* cur = ps->head;//先保存下一个结点,在释放当前结点,在重定位while (cur){QNode* Qnext = cur->next;free(cur);cur = Qnext;}ps->head = ps->tail = NULL;ps->size = 0;
}

🌕(十)、遍历

与栈类似的,队列遍历的时候也不用封装成函数,而是用循环,边遍历边出队,遍历完后,队列为空,这与其后面使用场景有着密切联系;

void Queuetest1()
{Que ps;Queueinit(&ps);QueuePush(&ps, 1);QueuePush(&ps, 2);QueuePush(&ps, 3);QueuePush(&ps, 4);QueuePush(&ps, 5);//遍历while (!QueueEmpty(&ps)){//当前数据是整形,所以占位符用%dprintf("%d ", QueueFront(&ps));QueuePop(&ps);}printf("\n");QueueDestroy(&ps);
}

先进先出,符合其特征;

🍁、队列实现源代码

🌕(一)、main.c


#include"Queue.h"void Queuetest1()
{Que ps;Queueinit(&ps);QueuePush(&ps, 1);QueuePush(&ps, 2);QueuePush(&ps, 3);QueuePush(&ps, 4);QueuePush(&ps, 5);//遍历while (!QueueEmpty(&ps)){//当前数据是整形,所以占位符用%dprintf("%d ", QueueFront(&ps));QueuePop(&ps);}printf("\n");QueueDestroy(&ps);
}int main()
{Queuetest1();return 0;
}

🌕(二)、Queue.c

#include"Queue.h"//初始化
void Queueinit(Que* ps)
{assert(ps);ps->head = ps->tail = NULL;ps->size = 0;
}//销毁
void QueueDestroy(Que* ps)
{assert(ps);QNode* cur = ps->head;//先保存下一个结点,在释放当前结点,在重定位while (cur){QNode* Qnext = cur->next;free(cur);cur = Qnext;}ps->head = ps->tail = NULL;ps->size = 0;
}//入队
void QueuePush(Que* ps, QDatatype x)
{assert(ps);//创建一个新结点QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc");return;}//因为是在尾结点入队,所以入队之后结点next域要置空newnode->data = x;newnode->next = NULL;//第一次插入是结构体指针之间的赋值,之后才是结构体成员的赋值,所以要分情况//记住tail指针始终指向尾结点,所以入队之后要对tail指针重定位if (ps->tail == NULL){ps->head = ps->tail = newnode;}else{ps->tail->next = newnode;ps->tail = newnode;}//入队后元素数量+1ps->size++;
}//出队
void QueuePop(Que* ps)
{assert(ps);//检查队列是否为空,若为空则assert函数报错提示assert(!QueueEmpty(ps));//队列不为空,进行尾删//当对列只剩下一个元素时,要注意head和tail指针都要指向NULL,所以为了安全起见,进行分类讨论if (ps->head->next == NULL){free(ps->head);//注意free释放的是该指针指向的空间,而不是释掉该指针ps->head = ps->tail = NULL;}else{QNode* next = ps->head->next;free(ps->head);ps->head = next;}//出队列,元素数量-1ps->size--;
}//取队头
QDatatype QueueFront(Que* ps)
{assert(ps);//检查队列为不为空assert(!QueueEmpty(ps));//返回首结点的data域return ps->head->data;
}//取队尾
QDatatype QueueBack(Que* ps)
{assert(ps);//检查队列为不为空assert(!QueueEmpty(ps));//返回尾结点的data域return ps->tail->data;
}//判空
bool QueueEmpty(Que* ps)
{assert(ps);//为空返回真,不为空返回假return (ps->head == NULL);
}//获取队列元素个数
int QueueSize(Que* ps)
{assert(ps);return ps->size;
}

🌕(三)、Queue.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
#include<stdlib.h>typedef int QDatatype;
typedef struct QueueNode
{struct QueueNode* next;QDatatype data;
}QNode;typedef struct Queue
{QNode* head;//头指针,指向首结点QNode* tail;//尾指针,指向为结点int size;//记录队列长度
}Que;//初始化
void Queueinit(Que* ps);//销毁
void QueueDestroy(Que* ps);//入队
void QueuePush(Que* ps,QDatatype x);//出队
void QueuePop(Que *ps);//取队头
QDatatype QueueFront(Que* ps);//取队尾
QDatatype QueueBack(Que* ps);//判空
bool QueueEmpty(Que* ps);//获取队列元素个数
int QueueSize(Que* ps);

本次知识到此结束,希望对你有所帮助

更多推荐

栈和队列(2)

本文发布于:2023-12-03 10:48:07,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1654511.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:队列

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!