当前位置: 首页 > news >正文

队列的实现

目录

1.概念与结构

2.队列的实现

2.1 初始化

2.2 入队列

2.3 判断队列是否为空

2.4 出队列

2.5 取队头数据和取队尾数据

2.6 队列有效元素个数

2.7 销毁

3.总结上述代码


我们解决算法题的时候常常会有不止一种方法来实现,所以不用的数据结构常常给人不同的想法,今天我们来看看队列的实现。

1.概念与结构

概念:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出的性质。

入队列:进行插入操作的一端称为队尾。

出队列:进行删除操作的一端称为对头。

下面进行实现的时候可以根据这张图片来进行操作。

队列底层结构选型:队列也可以数据和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

数组来实现时:插入数据的时间复杂度为O(1),删除数据的时间复杂度为O(n)。

链表来实现时:插入数据的时间复杂度为O(n),删除数据的时间复杂度为O(1)。

这样比较可能并没有对比性,如果时间复杂度比不了,那就比较空间复杂度。

数组的初始化空间有三项:

struct List
{SLDataType* a;int size;int capacity;
};

链表的初始化空间有两项:

struct List
{SLTDataType data;struct List* next;
};

这样一比较,就是链表的空间复杂度就比数组的空间复杂度更优一些。所以我们选择链表作为队列底层结构的选型。

2.队列的实现

首先,我们还是和之前实现的数据结构一样,创建一个头文件放函数的声明,创建一个.c文件放函数的实现,创建一个.c文件放主体函数。

首先我们要先进行队列结构的代码编写,如下:

//队列结构
struct Queue
{*phead;*ptail;
};

这样写那队列的节点类型就不知道了,而要定义队列节点的类型就只能再创建一个结构体。

typedef int QDataType;//队列节点结构
typedef struct QueueNode
{QDataType data;struct QueueNode* next;
}QueueNode;//队列结构
typedef struct Queue
{QueueNode* phead;QueueNode* ptail;
}Queue;

我们把队列重命名就可以得到以上代码。

队列的结构都解释完了,那么下面就开始初始化了。

2.1 初始化

跟之前链表定义一样,初始化就直接写了。

Queue.h

//初始化
void QueueInit(Queue* pq);

Queue.c

//初始化
void QueueInit(Queue* pq)
{assert(pq);pq->phead = pq->ptail = NULL;
}

写完这些代码后,我们再去test.c文件里去执行看看问题。

看调试结果得知,初始化完成。

2.2 入队列

先进行代码的编写,再根据代码结合图片进行解释。

Queue.h

//入队列--队尾
void QueuePush(Queue* pq, QDataType x);

Queue.c

//入队列--队尾
void QueuePush(Queue* pq, QDataType x)
{assert(pq);//创建一个新节点QueueNode* newnode = (QueueNode*)malloc(sizeof(QDataType));if (newnode == NULL){perror("malloc");exit(1);}newnode->data = x;newnode->next = NULL;//队列为空if (pq->phead == NULL){pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = pq->ptail->next;}
}

首先,入队列需要保证形参不能为空。进行创建一个新的节点newnode时需要用动态内存管理中的函数malloc函数。再进行判断newnode节点是否成功创建,如果不成功,则打印错误信息并退出。然后让newnode节点的数据进行整理。既然从队尾入队列,那么就有两种情况,第一种就是如果队列为空,那么对头和队尾都应该等于newnode节点。第二种就是队列中有数据,那么只让队尾保存的next指针指向newnode节点,再让队尾往后走就行了。这样就是入队成功。

test.c

	//入队列--队尾QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);

如图调试可得:对头为1,队尾为3,入队列成功。

2.3 判断队列是否为空

这里需要用到布尔类型,使用布尔类型时需要头文件#include<stdbool.h>。

Queue.h

//判断队列是否为空
bool QueueEmpty(Queue* pq);

Queue.c

//判断队列是否为空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;
}

判断队列是否为空,这里传队列的时候pq不能为空则找到队列。如果队列为空时,则对头为NULL。

2.4 出队列

Queue.h

//出队列--对头
void QueuePop(Queue* pq);

Queue.c

//出队列--对头
void QueuePop(Queue* pq)
{assert(!QueueEmpty(pq));//队列中只有一个节点if (pq->phead == pq->ptail){free(pq->phead);pq->phead = pq->ptail = NULL;}else{QueueNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}
}

出队列首先要确定的是队列不能为空,所以加了断言报错。队列中有两种情况,第一种是队列中只有一个节点,那就是对头和队尾都是同一个节点,我们把它释放掉,成为野指针后再置为NULL。第二种是队列中不止一个节点,我们需要出队列释放头结点时,需要将头节点的下一个节点进行保存,如果没保存释放掉头节点的话,就找不到下一个节点了。所以定义一个节点next为头节点的下一个节点,释放头节点后,并重新将头节点指向next节点。

调试如图所示,执行一步,便出队一个节点。

2.5 取队头数据和取队尾数据

Queue.h

//取队头数据
QDataType QueueFront(Queue* pq);
//取队尾数据
QDataType QueueBack(Queue* pq);

Queue.c

//取队头数据
QDataType QueueFront(Queue* pq)
{assert(!QueueEmpty(pq));return pq->phead->data;
}
//取队尾数据
QDataType QueueBack(Queue* pq)
{assert(!QueueEmpty(pq));return pq->ptail->data;
}

取队头数据和取队尾数据的前提都是队列不能为空,如果队列为空,就取不到队头和队尾数据了。返回值用QDataType来接收,所以不要用错数据类型和返回值类型。

2.6 队列有效元素个数

Queue.h

//队列有效元素个数
int QueueSize(Queue* pq);

Queue.c

//队列有效元素个数
int QueueSize(Queue* pq)
{assert(pq);QueueNode* pcur = pq->phead;int size = 0;while (pcur){++size;pcur = pcur->next;}return size;
}

要想求队列有效元素个数,则pq不能为空,如果为空,就找不到队列,所以断言报错。定义一个pcur节点的指针指向头节点。再定义一个计数器。进入循环遍历,如果pcur不等于NULL,就让size进行++,pcur往后走。跳出循环则有效个数求出。

2.7 销毁

Queue.h

//销毁
void QueueDestroy(Queue* pq);

Queue.c

//销毁
void QueueDestroy(Queue* pq)
{assert(pq);QueueNode* pcur = pq->phead;while (pcur){QueueNode* next = pcur->next;free(pcur);pcur = next;}pq->phead = pq->ptail = NULL;
}

要销毁链表,就先找到链表,所以先加断言报错。定义一个pcur指针指向头节点。让pcur进行循环遍历,如果pcur不为空,再定义一个next指针指向pcur的下一个节点,因为释放掉pcur之后得需要找到下一个节点。最后让pcur等于next就成功销毁第一个节点。循环往复,pcur为NULL时,销毁完毕。只剩下两个队头和队尾指针为野指针,再对他们置为NULL,销毁完毕。

3.总结上述代码

Queue.h

#pragma once#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int QDataType;typedef struct QueueNode
{QDataType data;struct QueueNode* next;
}QueueNode;typedef struct Queue
{QueueNode* phead;QueueNode* ptail;
}Queue;//初始化
void QueueInit(Queue* pq);//入队列--队尾
void QueuePush(Queue* pq, QDataType x);//判断队列是否为空
bool QueueEmpty(Queue* pq);//出队列--队头
void QueuePop(Queue* pq);//取队头数据
QDataType QueueFront(Queue* pq);
//取队尾数据
QDataType QueueBack(Queue* pq);//队列有效元素个数
int QueueSize(Queue* pq);//销毁
void QueueDestroy(Queue* pq);

Queue.c

#include"Queue.h"//初始化
void QueueInit(Queue* pq)
{assert(pq);pq->phead = pq->ptail = NULL;
}//入队列--队尾
void QueuePush(Queue* pq, QDataType x)
{assert(pq);//创建一个新节点QueueNode* newnode = (QueueNode*)malloc(sizeof(QDataType));if (newnode == NULL){perror("malloc");exit(1);}newnode->data = x;newnode->next = NULL;//队列为空if (pq->phead == NULL){pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = pq->ptail->next;}
}//判断队列是否为空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;
}//出队列--队头
void QueuePop(Queue* pq)
{assert(!QueueEmpty(pq));//队列中只有一个节点if (pq->phead == pq->ptail){free(pq->phead);pq->phead = pq->ptail = NULL;}else{QueueNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}
}//取队头数据
QDataType QueueFront(Queue* pq)
{assert(!QueueEmpty(pq));return pq->phead->data;
}
//取队尾数据
QDataType QueueBack(Queue* pq)
{assert(!QueueEmpty(pq));return pq->ptail->data;
}//队列有效元素个数
int QueueSize(Queue* pq)
{assert(pq);QueueNode* pcur = pq->phead;int size = 0;while (pcur){++size;pcur = pcur->next;}return size;
}//销毁
void QueueDestroy(Queue* pq)
{assert(pq);QueueNode* pcur = pq->phead;while (pcur){QueueNode* next = pcur->next;free(pcur);pcur = next;}pq->phead = pq->ptail = NULL;
}

test.c

#include"Queue.h"void test01()
{Queue q;//初始化QueueInit(&q);//入队列--队尾QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);////出队列--队头//QueuePop(&q);//QueuePop(&q);//QueuePop(&q);////取队头数据//int ret = QueueFront(&q);//printf("队头:%d\n", ret);////取队尾数据//int pop = QueueBack(&q);//printf("队尾:%d\n", pop);//队列有效元素个数/*printf("%d\n", QueueSize(&q));*///销毁QueueDestroy(&q);}int main()
{test01();return 0;
}

总结,数据结构就是要别画图理解代码,别看图想解决代码的过程。我们可以一起进步,加油!

http://www.dtcms.com/a/537544.html

相关文章:

  • undo表空间满会导致业务出问题吗
  • 电子商城网站建设流程贵州建设学校网站
  • h5游戏免费下载:地球日
  • 合肥万户网站建设wordpress主题怎么编辑
  • Redix数据库基础
  • 达内网站开发成功的软文营销案例
  • 哪里有配音的网站青岛专业做网站的公司有哪些
  • 机器视觉的手机模组背光贴合应用
  • LeetCode 每日一题 2025/10/20-2025/10/26
  • 怎么做招聘网站设计2023年做网站怎么样
  • 大气微电影类网站织梦模板完整版广州有什么好玩的地方景点推荐
  • 网站网站是怎么做的百度网盘网页版官网
  • 国外最新创意产品网站岳阳招聘网最新招聘
  • 东莞做网站需要避免这些因素WordPress如何导入本地插件
  • 网站设计与建设报告如何给给公司建立网站
  • 中航建设集团有限公司网站国际新闻界期刊
  • 合合信息与上海交通大学开展课题合作研究,共探智能文档图像处理前沿技术
  • 罗湖商城网站设计价格网站系统分析
  • 沈阳网站建设蓝顶网络wordpress怎么让手机端好看
  • Java---StringBuilder
  • 大航母网站建设怎么样防制网站怎么做
  • app分发平台哪个好点?手机app应用内测分发平台支持负载均衡的重要性
  • 华为ACT三步走”实施路径,以推动行业智能化落地
  • 深度解析Weights Biases:让AI实验管理变得如此简单
  • 国内模板建站公司爱网恋的男生
  • 网站优化预算表白网页生成器下载
  • 广州石井做网站建设银行怎么加入信用网站
  • 网站开发项目个人总结wordpress建图片网站
  • Spring Boot3零基础教程,swagger生成接口文档,笔记72
  • 做网站的登陆功能互联网信息服务