队列是一种种常见的数据结构,它用来解决一些数据类型的问题,那么好,我来带着大家来学习一下队列
我们学完了栈之后,紧接着再来了解一下队列的,和栈一样,是一种操作受限制的线性表
队列(queue):具有先进先出的特点,与栈是相反的。
特点:只允许在表的前端进行插入删除操作,在表的后端进行插入操作
实现一个队列的功能,需要有插入,删除,返回队头和队尾元素,队列大小,是否为空这些功能。
仔细想一下这些功能,使用单链表的方法是比较合适的
首先创建一个结构体来存放下一个节点和队列中该节点的值
typedef int qudatetype;
typedef struct queuenode {
qudatetype val;
struct queuende* next;
}qunode;
但是,我们需要返回队列的尾部元素,如果每次都遍历这个队列,会使时间复杂度较大,那么,我们需要一个指针来指向队列链表的尾部,这样可使效率提高
这里我们在创建一个结构体用来放队列的头节点和尾节点,在加上队列的大小
typedef struct queue {
qunode* phead;
qunode* ptail;
int size;
}qu;
这样我们一个队列的准备工作就完成了
下面我们开始队列的模拟实现,我们采用分模块的方式进行实现,这里,我在代码中会进行注释,可直接阅读代码来学习队列的实现。
queue.h用来声明函数
queue,c用来实现队列的各个功能
test.c用来测试队列
queue.h
#include
#include
#include
#include
typedef int qudatetype;
typedef struct queuenode {
qudatetype val;
struct queuende* next;
}qunode;
typedef struct queue {
qunode* phead;
qunode* ptail;
int size;
}qu;
//队列的初始化
void initqu(qu* pq);
void qudestroy(qu* pq);
//队列的插入和弹出
void queuepush(qu* pq,qudatetype x);
void queuepop(qu* pq);
//返回队列的头尾
qudatetype queuehead(qu* pq);
qudatetype queuetail(qu* pq);
//返回队列是否为空
bool queueempty(qu* pq);
//返回队列长度
int queuesize(qu* pq);
queue.c
#include"queue.h"
//队列的初始化
void initqu(qu* pq)
{
assert(pq);
pq->size = 0;
pq->phead = pq->ptail = NULL;
}
//队列的销毁
void qudestroy(qu* pq)
{
assert(pq);//断言
qunode* cur = pq->phead;
while (cur)//遍历一下队列,依次进行内存释放
{
qunode* next = cur->next;
free(cur);
cur = next;
}
pq->phead = pq->ptail = NULL;
pq->size = 0;//收尾
}
//队列的插入和弹出
void queuepush(qu* pq, qudatetype x)
{
assert(pq);
qunode* newnode = (qunode*)malloc(sizeof(qunode));//创建新节点
assert(newnode);//断言,如果开辟内存失败,程序终止
//对节点进行初始化
newnode->val = x;
newnode->next = NULL;
//如果是第一次插入,执行if中的操作
if (pq->phead == NULL)
pq->phead = pq->ptail = newnode;
//否则,执行else中的操作
else
{
pq->ptail->next = newnode;
pq->ptail = newnode;//更新ptail指向队列尾部
}
pq->size++;//大小自增
}
void queuepop(qu* pq)
{
assert(pq);
assert(pq->phead);//队列为空,无法删除,程序终止
qunode* del = pq->phead;
pq->phead = pq->phead->next;
free(del);
del = NULL;
如果队列中只有一个元素,执行以下操作
if (pq->phead == NULL)
pq->ptail = NULL;
pq->size--;
}
//返回队列的头尾
qudatetype queuehead(qu* pq)
{
assert(pq);
assert(pq->phead);
return pq->phead->val;
}
qudatetype queuetail(qu* pq)
{
assert(pq);
assert(pq->ptail);
return pq->ptail->val;
}
//返回队列是否为空
bool queueempty(qu* pq)
{
assert(pq);
return pq->size == 0;//size为0,为真返回1,反之,返回0
}
//返回队列长度
int queuesize(qu* pq)
{
assert(pq);
return pq->size;
}
test.c
#include"queue.h"
int main()
{
qu q;
initqu(&q);
queuepush(&q, 1);
queuepush(&q, 2);
queuepush(&q, 3);
queuepush(&q, 4);
queuepop(&q);
queuepop(&q);
queuepop(&q);
while (!queueempty(&q))
{
printf("%d---", queuehead(&q));
queuepop(&q);
}
qudestroy(&q);
return 0;
}
趁热打铁,做一道题,练习一下队列
先来看一下这道题
https://leetcode.cn/problems/implement-stack-using-queues/
使用队列来实现栈的功能
思路
我们浅浅思考一下,栈和队列的特点,栈是先进后出,队列是先进先出,这样,我们可以利用两个队列来实现一个栈的功能,
假设一个队列1,2,3,4,5;我们可以把它们的前4个元素,导入到另一个空队列中,变成1,2,3,4;然后把剩下的5删除,这样我们就达到了栈的先进后出的特点了。其他的功能也是比较容易实现的
代码实现
typedef int qudatetype;
typedef struct queuenode {
qudatetype val;
struct queuende* next;
}qunode;
typedef struct queue {
qunode* phead;
qunode* ptail;
int size;
}qu;
void initqu(qu* pq)
{
assert(pq);
pq->size = 0;
pq->phead = pq->ptail = NULL;
}
//队列的销毁
void qudestroy(qu* pq)
{
assert(pq);
qunode* cur = pq->phead;
while (cur)
{
qunode* next = cur->next;
free(cur);
cur = next;
}
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
//队列的插入和弹出
void queuepush(qu* pq, qudatetype x)
{
assert(pq);
qunode* newnode = (qunode*)malloc(sizeof(qunode));
assert(newnode);
newnode->val = x;
newnode->next = NULL;
if (pq->phead == NULL)
pq->phead = pq->ptail = newnode;
else
{
pq->ptail->next = newnode;
pq->ptail = newnode;
}
pq->size++;
}
void queuepop(qu* pq)
{
assert(pq);
assert(pq->phead);
qunode* del = pq->phead;
pq->phead = pq->phead->next;
free(del);
del = NULL;
if (pq->phead == NULL)
pq->ptail = NULL;
pq->size--;
}
//返回队列的头尾
qudatetype queuehead(qu* pq)
{
assert(pq);
assert(pq->phead);
return pq->phead->val;
}
qudatetype queuetail(qu* pq)
{
assert(pq);
assert(pq->ptail);
return pq->ptail->val;
}
//返回队列是否为空
bool queueempty(qu* pq)
{
assert(pq);
return pq->size == 0;
}
//返回队列长度
int queuesize(qu* pq)
{
assert(pq);
return pq->size;
}
typedef struct {
qu q1;
qu q2;
} MyStack;
MyStack* myStackCreate() {
MyStack*pst=(MyStack*)malloc(sizeof(MyStack));
initqu(&pst->q1);
initqu(&pst->q2);
return pst;
}
void myStackPush(MyStack* obj, int x) {
if(!queueempty(&obj->q1))
{
queuepush(&obj->q1,x);
}
else
{
queuepush(&obj->q2,x);
}
}
int myStackPop(MyStack* obj) {
qu *empty=&obj->q1;
qu *nonempty=&obj->q2;
if(!queueempty(empty))
{
empty=&obj->q2;
nonempty=&obj->q1;
}
while(queuesize(nonempty)>1)
{
queuepush(empty,queuehead(nonempty));
queuepop(nonempty);
}
int top=queuehead(nonempty);
queuepop(nonempty);
return top;
}
int myStackTop(MyStack* obj) {
if(queueempty(&obj->q1))
return queuetail(&obj->q2);
return queuetail(&obj->q1);
}
bool myStackEmpty(MyStack* obj) {
return queueempty(&obj->q1)&&queueempty(&obj->q2);
}
void myStackFree(MyStack* obj) {
qudestroy(&obj->q1);
qudestroy(&obj->q2);
free(obj);
}
/**
* Your MyStack struct will be instantiated and called as such:
* MyStack* obj = myStackCreate();
* myStackPush(obj, x);
* int param_2 = myStackPop(obj);
* int param_3 = myStackTop(obj);
* bool param_4 = myStackEmpty(obj);
* myStackFree(obj);
*/
这道题有了思路代码还是很好理解的,大家可以参考一下通过的代码,自己去oj一下
栈和队列的讲解就到这里了。大家有不同的见解可以一起交流一下
感谢观看,有错误或不足请指出