栈和队列(stack和queue)
创始人
2025-05-31 01:53:00

目录

  • 一、栈
    • 1.1 什么是栈?
    • 1.2 栈的相关操作
      • 1.2.1 结构体变量的声明
      • 1.2.2 栈的初始化
      • 1.2.3 栈的销毁
      • 1.2.4 元素入栈
      • 1.2.5 元素出栈
      • 1.2.6 取栈顶元素
      • 1.2.7 求栈顶元素的数目
      • 1.2.8 判断栈是否为空
    • 1.3 栈的代码汇总
      • 1.3.1 Stack.h
      • 1.3.2 Stack.c
      • 1.3.3 test.c
  • 二、队列
    • 2.1 什么是队列?
    • 2.2 队列相关操作
      • 2.2.1 结构体变量的声明
      • 2.2.2 队列的初始化
      • 2.2.3 队列的销毁
      • 2.2.4 队列的插入
      • 2.2.5 队列的删除
      • 2.2.6 队列元素的数目
      • 2.2.7 判断队列是否为空
      • 2.2.8 取队列头部的元素
      • 2.2.9 取队列尾部的元素
    • 2.3 队列的代码汇总
      • 2.3.1 Queue.h
      • 2.3.2 Queue.c
      • 2.3.3 test.c

一、栈

1.1 什么是栈?

栈 (Stack)是一种线性存储结构,它具有如下特点: 栈中的数据元素遵守”后进先出” (First In Last Out)的原则,简称FILO结构。 限定只能在栈顶进行插入和删除操作。
栈顶与栈底:允许元素插入与删除的一端称为栈顶,另一端称为栈底。栈可以用动态数组的方式实现,也可以用链表来实现。以下是用动态数组的方式模拟实现栈。

1.2 栈的相关操作

1.2.1 结构体变量的声明

typedef int StackDataType;typedef struct Stack
{//这里就是一个指向动态开辟内存的指针即可//和顺序表一个道理StackDataType* a;//top记录栈顶位置,top的初始值为0或者-1取决于//设计者设计top位置是栈顶元素的位置(top=-1)//还是栈顶元素位置的下一个(top=0)。int top;//capacity是栈的容量,容量不够就增容int capacity;
}ST;

1.2.2 栈的初始化

void STInit(ST* st)
{assert(st);//开辟空间st->a = (StackDataType*)malloc(sizeof(StackDataType) * 4);if (st->a == NULL){perror("malloc fail");return;}st->capacity = 4;//st->top=0代表top是栈顶元素的下一个位置的下标而并非栈顶元素的下标st->top = 0;
}

1.2.3 栈的销毁

void STDestroy(ST* st)
{assert(st);free(st->a);st->a = NULL;st->capacity = 0;st->top = 0;}

1.2.4 元素入栈

void STPush(ST* st, StackDataType x)
{assert(st);if (st->capacity == st->top){//增容StackDataType* tmp = (StackDataType*)realloc(st->a, sizeof(StackDataType) * (st->capacity * 2));if (tmp == NULL){perror("realloc fail");return;}st->a = tmp;st->capacity *= 2;}//top位置是栈顶元素位置的下一个,所以直接把x入栈到top下标的位置st->a[st->top] = x;st->top++;}

1.2.5 元素出栈

void STPop(ST* st)
{//出栈的条件之一是栈内必须有数据//所以不能为空assert(st && !STEmpty(st));//直接top--即可st->top--;
}

1.2.6 取栈顶元素

StackDataType STTop(ST* st)
{assert(st);//要取元素,栈不能为空assert(!STEmpty(st));//由于top是栈顶的下一个位置的下标,所以需要返回top-1位置的元素return st->a[st->top - 1];
}

1.2.7 求栈顶元素的数目

size_t STSize(ST* st)
{assert(st);//由于top是有0开始的,插入一个数据就+1//所以插入了多少个数据top就是多少,所以直接返回top的大小即可return st->top;
}

1.2.8 判断栈是否为空

bool STEmpty(ST* st)
{assert(st);//如果top==0,证明栈内无数据,//栈为空,st->top==0的逻辑结果true,直接返回即可return st->top == 0;
}

1.3 栈的代码汇总

1.3.1 Stack.h

#pragma once#include 
#include 
#include 
#include typedef int StackDataType;typedef struct Stack
{StackDataType* a;int top;int capacity;
}ST;extern void STInit(ST* st);
extern void STDestroy(ST* st);
extern void STPush(ST* st, StackDataType x);
extern void STPop(ST* st);
extern StackDataType STTop(ST* st);
extern size_t STSize(ST* st);
extern bool STEmpty(ST* st);

1.3.2 Stack.c

#define _CRT_SECURE_NO_WARNINGS 1#include "Stack.h"void STInit(ST* st)
{assert(st);//开辟空间st->a = (StackDataType*)malloc(sizeof(StackDataType) * 4);if (st->a == NULL){perror("malloc fail");return;}st->capacity = 4;//st->top=0代表top是栈顶元素的下一个的位置的下标而并非栈顶元素的下标st->top = 0;
}void STDestroy(ST* st)
{assert(st);free(st->a);st->a = NULL;st->capacity = 0;st->top = 0;}void STPush(ST* st, StackDataType x)
{assert(st);if (st->capacity == st->top){//增容StackDataType* tmp = (StackDataType*)realloc(st->a, sizeof(StackDataType) * (st->capacity * 2));if (tmp == NULL){perror("realloc fail");return;}st->a = tmp;st->capacity *= 2;}//top位置是栈顶元素位置的下一个,所以直接把x入栈到top下标的位置st->a[st->top] = x;st->top++;}void STPop(ST* st)
{assert(st && !STEmpty(st));//直接top--即可st->top--;
}StackDataType STTop(ST* st)
{assert(st);//要取元素,栈不能为空assert(!STEmpty(st));//由于top是栈顶的下一个位置的下标,所以需要返回top-1位置的元素return st->a[st->top - 1];
}size_t STSize(ST* st)
{assert(st);//由于top是有0开始的,插入一个数据就+1//所以插入了多少个数据top就是多少,所以直接返回top的大小即可return st->top;
}bool STEmpty(ST* st)
{assert(st);//如果top==0,证明栈内无数据,//栈为空,st->top==0的逻辑结果true,直接返回即可return st->top == 0;
}

1.3.3 test.c

#define _CRT_SECURE_NO_WARNINGS 1#include "Stack.h"int main()
{ST st;STInit(&st);STPush(&st, 1);STPush(&st, 2);STPush(&st, 3);STPush(&st, 4);STPush(&st, 5);while (!STEmpty(&st)){printf("%d ", STTop(&st));STPop(&st);}printf("\n");STDestroy(&st);return 0;
}

二、队列

2.1 什么是队列?

队列(Queue)也是一种线性的存储结构,它具有如下特点: 队列中的数据元素遵守”先进先出” (First In First Out)的原则,简称FIFO结构。 限定只能在队列的尾部进行插入数据,头部进行删除数据。
队列适合用单链表实现,因为单链表头删和尾插的时间复杂度是O(1)的,效率很高。

2.2 队列相关操作

2.2.1 结构体变量的声明

typedef int QNodeDataType;//队列的每一个元素是一个结构体
typedef struct QueueNode
{//每一个结点内都存着下一个结点的指针(地址)struct QueueNode* next;//结点的有效数据QNodeDataType data;}QNode;typedef struct Queue
{//队列最好定义一个指向头节点的指针和//一个指向尾节点的指针,方便头删和尾插,提高效率QNode* head;QNode* tail;//记录队列一共有多少个结点,每插入一个结点就+1int size;}Queue;

2.2.2 队列的初始化

void QueueInit(Queue* pq)
{assert(pq);//空队列的头和尾指针都要指向NULLpq->head = NULL;pq->tail = NULL;pq->size = 0;}

2.2.3 队列的销毁

void QueueDestroy(Queue* pq)
{assert(pq);//由于每一个结点都是malloc出来的,所以//需要遍历逐一释放队列内的结点,防止内存泄露QNode* cur = pq->head;while (cur){//先保存需要释放的结点del,释放后cur迭代地走下去//直到cur为空就全部释放完了QNode* del = cur;cur = cur->next;free(del);del = NULL;}pq->head = NULL;pq->tail = NULL;pq->size = 0;
}

2.2.4 队列的插入

void QueuePush(Queue* pq, QNodeDataType x)
{assert(pq);//申请结点QNode* newNode = (QNode*)malloc(sizeof(QNode));if (newNode == NULL){perror("");return;}newNode->data = x;newNode->next = NULL;//第一次插入时由于队列为空,所以pq->head和pq->tail//都为空,则应该直接赋值结点的结构体给p->head和pq->tail//如果直接pq->tail->next = newNode程序会崩的,因为pq->tail为空//不能访问if (pq->head == NULL){pq->head = pq->tail = newNode;}else{//插入到尾部pq->tail->next = newNode;//newNode更新为新的尾结点pq->tail = newNode;}//队列的数据数目+1pq->size++;
}

2.2.5 队列的删除

void QueuePop(Queue* pq)
{assert(pq);//删除的前提是不能队列为空assert(!QueueEmpty(pq));//如果只有一个结点的话,那删掉这个结点//同时把尾指针要置为NULL,不置空的话//尾指针就是一个野指针,存在越界访问的风险if (pq->head->next == NULL){free(pq->head);pq->head = pq->tail = NULL;}else{//先保存下一个结点的地址,再释放当前的结点QNode* next = pq->head->next;free(pq->head);pq->head = next;}//数目-1pq->size--;}

2.2.6 队列元素的数目

int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}

2.2.7 判断队列是否为空

bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}

2.2.8 取队列头部的元素

QNodeDataType QueueFront(Queue* pq)
{assert(pq);//取元素的前提是队列不能为空assert(!QueueEmpty(pq));return pq->head->data;
}

2.2.9 取队列尾部的元素

QNodeDataType QueueBack(Queue* pq)
{assert(pq);//取元素的前提是队列不能为空assert(!QueueEmpty(pq));return pq->tail->data;}

2.3 队列的代码汇总

2.3.1 Queue.h

#pragma once#include 
#include 
#include 
#include typedef int QNodeDataType;typedef struct QueueNode
{struct QueueNode* next;QNodeDataType data;}QNode;typedef struct Queue
{QNode* head;QNode* tail;int size;}Queue;extern void QueueInit(Queue* pq);
extern void QueueDestroy(Queue* pq);
extern void QueuePush(Queue* pq, QNodeDataType x);
extern void QueuePop(Queue* pq);
extern int QueueSize(Queue* pq);
extern bool QueueEmpty(Queue* pq);
extern QNodeDataType QueueFront(Queue* pq);
extern QNodeDataType QueueBack(Queue* pq);

2.3.2 Queue.c

#define _CRT_SECURE_NO_WARNINGS 1#include "Queue.h"void QueueInit(Queue* pq)
{assert(pq);pq->head = NULL;pq->tail = NULL;pq->size = 0;}void QueueDestroy(Queue* pq)
{assert(pq);//由于每一个结点都是malloc出来的,所以//需要遍历逐一释放队列内的结点,防止内存泄露QNode* cur = pq->head;while (cur){//先保存需要释放的结点del,释放后cur迭代地走下去//直到cur为空就全部释放完了QNode* del = cur;cur = cur->next;free(del);del = NULL;}pq->head = NULL;pq->tail = NULL;pq->size = 0;
}void QueuePush(Queue* pq, QNodeDataType x)
{assert(pq);//申请结点QNode* newNode = (QNode*)malloc(sizeof(QNode));if (newNode == NULL){perror("");return;}newNode->data = x;newNode->next = NULL;//第一次插入时由于队列为空,所以pq->head和pq->tail//都为空,则应该直接赋值结点的结构体给p->head和pq->tail//如果直接pq->tail->next = newNode程序会崩的,因为pq->tail为空//不能访问if (pq->head == NULL){pq->head = pq->tail = newNode;}else{//插入到尾部pq->tail->next = newNode;//newNode更新为新的尾结点pq->tail = newNode;}//队列的数据数目+1pq->size++;
}void QueuePop(Queue* pq)
{assert(pq);//删除的前提是不能队列为空assert(!QueueEmpty(pq));//如果只有一个结点的话,那删掉这个结点//同时把尾指针要置为NULL,不置空的话//尾指针就是一个野指针,存在越界访问的风险if (pq->head->next == NULL){free(pq->head);pq->head = pq->tail = NULL;}else{//先保存下一个结点的地址,再释放当前的结点QNode* next = pq->head->next;free(pq->head);pq->head = next;}//数目-1pq->size--;}int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}QNodeDataType QueueFront(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->head->data;
}QNodeDataType QueueBack(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->tail->data;}

2.3.3 test.c

#define _CRT_SECURE_NO_WARNINGS 1#include "Queue.h"int main()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);QueuePush(&q, 5);/*printf("%d ", QueueFront(&q));QueuePop(&q);printf("%d ", QueueFront(&q));QueuePop(&q);*/while (!QueueEmpty(&q)){printf("QueueFront:%d ", QueueFront(&q));printf("size = %d\n", QueueSize(&q));QueuePop(&q);}QueueDestroy(&q);return 0;
}

以上就是用C语言实现栈和队列的所有内容,你学会了吗?喜欢的在评论区留下一颗小心心点点关注呗!!!

上一篇:Hive

下一篇:MyBatis级联一对一与一对多

相关内容

热门资讯

用队列实现栈和用栈实现队列(C... 目录 一、用队列实现栈 二、 用栈实现队列 一、用队列实现栈 请你仅使用两个队列实现一个后入先出&...
代码随想录刷题-哈希表-两数之... 文章目录两数之和习题暴力解法哈希表 两数之和 本节对应代码随想录中:代码随想录...
凌恩生物明星产品:让你读懂细胞... 叶绿体和线粒体是真核细胞中不可或缺的重要细胞器,是第二套遗传信息系统,与...
密码如何“加盐加密”处理?程序... 目录 前言 一、手写加盐算法 1.1、加密 1.1.1、加密思路 1.1.2、加密简图 1.1.3、...
黑化什么意思网络用语 极速百科... 黑化,词语,也可指性情大变,比如原本某A是个文青,温文尔雅,突然某天某A大开杀戒,残忍无比,这就是所...
带有古和今的成语,古今的对话:... 带有古和今的成语有很多,例如:古为今用、古往今来、古稀之年、古今中外等等。这些成语都包含了古代和现代...
能力强的人有什么特点,标题建议... 能力强的人往往具备以下特点: 1. 学习能力:能力强的人通常能够快速学习新知识和技能,并能够灵...
跑步机怎么操作大图 极速百科网... 1. 启动跑步机:首先,确保跑步机已经插上电源,然后打开跑步机的电源开关。大多数跑步机都有一个启动/...
ELK+Filebeat+Ka... 文章目录ELK+Filebeat+Kafka分布式日志管理平台搭建为什么选择ELK&...
哈希结构的代码实现(开散列、闭... 哈希结构 unordered系列的关联式容器之所以查找效率比较高,是因为其底层使用了哈...
Java Annotation... 注解 注解(Annotation),又称元数据ÿ...
bim装配式工程师证书有用吗,... 首先,我们需要明确一点,那就是BIM装配式工程师证书肯定是有用的。这个证书证明了持有人掌握了BIM技...
什么东西可以深层清洁毛孔 极速... 首先,我们要明白,毛孔的深层清洁不仅仅是指清洁面部皮肤,还包括清洁身体和头发的毛孔。接下来,我将为你...
vip全称 极速百科网 极速百... VIP的英文全称为Very Important Person,中文翻译为重要人物、要员。一般指VIP...
公共交通工具有哪些 极速百科网... 1. 城市公交:这是大家最熟悉的公共交通工具之一,提供在城市内部的运输服务。公交车根据不同的大小和座...
智能火焰与烟雾检测系统(Pyt... 摘要:智能火焰与烟雾检测系统用于智能日常火灾检测报警,利用摄像头画面实时...
【学习笔记】《Writing ... 文章目录14 Energizing Writing 充满活力的写作14.1. ACTIVE VERS...
基于R语言因果关系推断模型实践... 通过数据得到可靠的因果关系一直是科学研究的主要目标之一。对因果关系的研究已经有千年之久;...
手机qq里怎么分组,手机QQ分... 1. 打开QQ应用,进入联系人界面。 2. 找到你想要分组的联系人或群聊。 3. 长按想...
带指的成语有哪些 极速百科网 ... 指日高升、一指蔽目、屈指可数、十指连心、三指佞臣、染指垂涎、戟指怒目、屈指可数。 如需更多含有...
第十八天 Vue-前端工程化总... 目录 Vue-前端工程化 1. 前后端分离开发 1.1 介绍 1.2 Yapi 2. 前端工程化 2...
急用钱公积金怎么提现,公积金提... 1. 了解公积金提现的条件和手续。在您考虑提现之前,请务必了解您所在地区的具体规定和要求。通常,您需...
杯子刻字励志八个字,志存高远,... 杯子刻字励志八个字建议如下: 1. 志存高远,自强不息。 2. 持之以恒,锐意进取。 ...
YOLOV4详解 1. 为什么要学习YOLOV4? 通过学习YOLOV3这个很重要的算法, 可以学习到作者重新设计Da...
提高曝光率:外贸网站如何充分利... 自从我从事外贸行业以来,谷歌优化一直是我关注的重点。 作为一个外贸从业者,...
Vue3 学习总结补充(一) 文章目录1、Vue3中为什么修改变量的值后,视图不更新?2、使用 ref...
锤哥和锤弟是双胞胎吗,锤哥和锤... 锤哥和锤弟是双胞胎吗?锤哥和锤弟这两个名字可能只是表示两个有亲属关系的人,而并不一定表示他们是双胞胎...
ido什么意思,IDO:意义、... IDO全称“I Do”,源自婚礼誓言,意为“我愿意”。表达对爱情的坚守。IDO钻戒的寓意是珍视爱情的...
形容夜色美的唯美句子,夜色的魅... 1. 夜幕降临,华灯初上,整个城市被柔和的灯光笼罩,宛如一颗璀璨的明珠。 2. 夜色中的星空,...
已婚女人梦见龙预示有什么征兆,... 已婚女人梦见龙,一般来说,是一种非常吉祥的预兆。在中国传统文化中,龙象征着富贵、吉祥和好运。 ...