数据结构--栈与队列

目录


前言

1.栈

1.1栈的概念及结构

 1.2接口函数

 1.3函数实现

1.4如何使用

2.队列 

2.1队列的概念及结构

2.2接口函数

 2.3函数实现

2.4如何使用


前言

        前面我们已经学习了顺序表和链表,今天我们来学习栈与队列,这两种结构也属于线性表,实际上就是顺序表和链表结构的延展。


1.栈


1.1栈的概念及结构

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
出栈:栈的删除操作叫做出栈。出数据也在栈顶


 1.2接口函数

        栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>// 下面是定长的静态栈的结构,实际中一般不实用,所以我们主要实现下面的支持动态增长的栈
typedef int STDataType;// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{STDataType* _a;int _top; // 栈顶int _capacity; // 容量
}Stack;
// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
bool StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);

 1.3函数实现

1.单个节点成员介绍

typedef struct Stack
{STDataType* _a;int _top; // 栈顶int _capacity; // 容量
}Stack;

        在这里我们使用顺序表来实现栈结构,当然使用单链表,双向链表也可以。我们可以看到有成员top,它是用来指向栈顶元素的,当然也可以指向栈顶元素的下一个,这取决于你的实现逻辑。这里的顺序表,显然也是动态的。


2.初始化栈

void StackInit(Stack* ps)
{assert(ps);ps->_a = NULL;ps->_capacity = NULL;ps->_top = 0;}

        关于top的初始化值的问题。

 这里可以将top初识化为0,当然也可以将top初始化为-1。这两种逻辑有何不同呢?

        1.将top初识化为0,假如在top位置插入一个数据,那么top就要向后移动一位。如果top不像后移动一位,那么就区分不了0位置是有数据还是没有数据了。所以top==0时,top表示的是指向栈顶元素的后一位。        

        2.将top初识化为-1,假如在top位置插入一个数据当然也是要向后面移动一位 。所以当top==-1时,top表示的时指向栈顶元素。

        在这里我是将top初始化为0了。


3.入栈

void StackPush(Stack* ps, STDataType data)
{assert(ps);if (ps->_top == ps->_capacity){int newcapacity = ps->_capacity == 0 ? 4 : 2 * ps->_capacity;Stack* tmp = (Stack*)realloc(ps->_a, sizeof(Stack) * newcapacity);if (tmp == NULL){perror("realloc");return;}ps->_a = tmp;ps->_capacity = newcapacity;}ps->_a[ps->_top] = data;ps->_top++;
}

        要实现入栈操作是十分简单的,首先要创建一个新的节点,在这扩容操作没必要单独封装,因为只有入栈操作时才用的到。不要忘记断言。

        插入操作是十分简单的,只需要在top位置插入,再让top指针向后移动就好了。


4.出栈

void StackPop(Stack* ps)
{assert(ps);assert(ps->_top > 0);ps->_top--;
}

        出栈操作也是十分简单,只需要让top向前移动一位就好了。


5.返回栈顶元素

STDataType StackTop(Stack* ps)
{assert(ps);assert(ps->_top > 0);return ps->_a[ps->_top - 1];
}

        进行栈顶元素返回操作的时候,需要注意的是,要将top-1,因为top是指向栈顶元素的下一个位置。


6.获取栈中有效元素个数

int StackSize(Stack* ps)
{assert(ps);return ps->_top;
}

        直接返回top的值就好了,在此逻辑种top值就是元素的个数。


7.检测栈是否为空

bool StackEmpty(Stack* ps)
{assert(ps);return ps->_top == 0;//等于0为真,否则假
}

        在此逻辑下,top值为空就代表栈为空,所以只需要判断top是否为0就好了,真则返回true,假则返回false。


8.销毁栈

void StackDestroy(Stack* ps)
{assert(ps);free(ps->_a);ps->_capacity = 0;ps->_top = 0;
}

        因为是用顺序表实现栈的,所以直接free掉malloc出来的空间就好了。

完!!!


1.4如何使用

 

int main()
{Stack s;StackInit(&s);StackPush(&s, 1);StackPush(&s, 2);StackPush(&s, 3);printf("栈内又%d个数据\n", StackSize(&s));while (!StackEmpty(&s)){printf("%d\n", StackTop(&s));StackPop(&s);}printf("\n");StackDestroy(&s);return 0;
}

        我们要获取栈内元素时,可以利用循环操作,直到栈内数据为空,要注意的是,每获取一次栈顶元素时,要进行出栈操作,才能取到下一个数据。

        值得一提的是:如果入栈时,在数据没有全部入栈时,突然出栈一个数据,然后在进行入栈,最后数据的顺序会被打乱

int main()
{Stack s;StackInit(&s);StackPush(&s, 1);StackPush(&s, 2);printf("%d\n", StackTop(&s));StackPop(&s);StackPush(&s, 3);printf("栈内又%d个数据\n", StackSize(&s));while (!StackEmpty(&s)){printf("%d\n", StackTop(&s));StackPop(&s);}printf("\n");StackDestroy(&s);return 0;
}


2.队列 


2.1队列的概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)

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

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


2.2接口函数

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

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
// 链式结构:表示队列
typedef int QDataType;
typedef struct QListNode
{struct QListNode* _pNext;QDataType _data;
}QNode;
// 队列的结构
typedef struct Queue
{QNode* _front;QNode* _rear;int size;
}Queue;
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);

 2.3函数实现

1.单个节点成员介绍

typedef struct QListNode
{struct QListNode* _pNext;QDataType _data;
}QNode;
// 队列的结构
typedef struct Queue
{QNode* _front;QNode* _rear;int size;
}Queue;

        

        实现队列我们使用头尾两个指针是最优的,但为什么,不在实现函数内直接定义,而直接在结构体内封装头和尾呢?这样做可以避免二级指针发的使用。如果队列为空,第一次进行入队操作时,就涉及到要改变结构体指针的操作,这时我们就要用到结构体指针的指针,也就是二级指针。但如果,像这样封装一下,就起到了哨兵位的作用就不用传二级指针了。


2.初始化队列

void QueueInit(Queue* q)
{assert(q);q->_front=q->_rear = NULL;q->size = 0;
}

3.队尾入队列

void QueuePush(Queue* q, QDataType data)
{assert(q);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->_data = data;newnode->_pNext = NULL;if (q->_rear == NULL){q->_front = q->_rear = newnode;}else{q->_rear->_pNext = newnode;q->_rear = newnode;}q->size++;
}

        入队列操是十分简单的,只需要利用队尾指针添加新节点就好了。


4.队头出队列

void QueuePop(Queue* q)
{assert(q);assert(q->_front);QNode* cur = q->_front;q->_front = q->_front->_pNext;free(cur);cur = NULL;if (q->_front == NULL)q->_rear = NULL;q->size--;
}

        在进行出队操作时,注意保存队头的下一个节点,然后free出队。要注意的是,队列数据为空,就不能进行出队操作了,可以进行断言assert(q->_front)防止。当只剩一个节点的时候,头尾指针指向一个节点,这是就要判断队头是否为空,如果为空,那也要将尾指针置空,防止野指针。


5.获取队列头部元素

QDataType QueueFront(Queue* q)
{assert(q);assert(q->_front);return q->_front->_data;}

6.获取队列尾部元素

QDataType QueueBack(Queue* q)
{assert(q);assert(q->_rear);return q->_rear->_data;
}

7.获取队列中有效元素个数

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

8.检查队列是否为空

bool QueueEmpty(Queue* q)
{assert(q);return q->_front == NULL;
}

        这里只需要检查对头是否为空就好了。


9.销毁队列

void QueueDestroy(Queue* q)
{assert(q);QNode* cur = q->_front;while (cur){QNode* next = cur->_pNext;free(cur);cur = next;}q->_front = q->_rear = NULL;q->size = 0;
}

        这里我们依然是保存后一个,销毁当前节点,所有节点都销毁后,将头尾指针置空。

完!!!


2.4如何使用

int main()
{Queue s;QueueInit(&s);QueuePush(&s, 1);QueuePush(&s, 2);QueuePush(&s, 3);QueuePush(&s, 4);QueuePush(&s, 5);printf("%d个元素\n", QueueSize(&s));while (!QueueEmpty(&s)){printf("%d ", QueueFront(&s));QueuePop(&s);}QueueDestroy(&s);return 0;
}

        这里我们也是利用循环,将所有数据获取,获取一个数据,出一个数据。

值得一提的是:如果入队时,在数据没有全部入栈时,突然出队一个数据,然后在进行入栈,最后数据的顺序也不会被打乱

int main()
{Queue s;QueueInit(&s);QueuePush(&s, 1);QueuePush(&s, 2);QueuePush(&s, 3);QueuePush(&s, 4);printf("%d\n", QueueFront(&s));QueuePop(&s);QueuePush(&s, 5);printf("%d个元素\n", QueueSize(&s));while (!QueueEmpty(&s)){printf("%d ", QueueFront(&s));QueuePop(&s);}QueueDestroy(&s);return 0;
}

希望这篇文章对你有帮助!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/196199.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

顺序表(数据结构与算法)

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ &#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1…

从0开始学习JavaScript--JavaScript 流程控制

JavaScript中的流程控制结构是编写结构化、可读性强的代码的关键。本文将深入研究JavaScript中的流程控制&#xff0c;包括条件语句、循环结构、跳转语句等&#xff0c;并通过丰富的示例代码来更全面地了解和运用这些概念。 条件语句 条件语句用于基于不同的条件执行不同的代…

架构开发与优化咨询和实施服务

服务概述 得益于硬件平台算力的提升&#xff0c;汽车电子电气架构的集成度逐渐提高&#xff0c;从单体ECU、到功能域集成控制器、到区域集成控制器&#xff0c;多域融合成为了目前行业中软件工程的重要工作内容。同时&#xff0c;在传统控制器C代码开发的基础上&#xff0c;C、…

C#中.NET 7.0 Windows窗体应用通过EF访问新建数据库

目录 一、 操作步骤 二、编写EF模型和数据库上下文 三、移植&#xff08;Migrations&#xff09;数据库 四、编写应用程序 五、生成效果 前文已经说过.NET Framework4.8 控制台应用通过EF访问已经建立的和新建的数据库。 前文已经说过.NET 6.0 控制台应用通过EF访问…

μC/OS-II---事件标志组管理1(os_flag.c)

目录 事件标志组创建事件标志组删除事件标志组获取/等待 当任务要与多个事件同步时&#xff0c;就要使用事件标志组。一个事件标志就是一个二值信号&#xff0c;事件标志组是若干二值信号的组合。使用事件标志组同步任务分为独立性同步和关联性同步。 事件标志组创建 flags&a…

MySql分区

一、什么是分区 MySQL分区是一种数据库设计和管理技术&#xff0c;它允许你将表分割成独立的、具有特定规则的存储单元。每个分区可以独立地进行管理&#xff0c;包括备份、恢复和优化。分区的主要目的是提高查询性能、简化维护以及实现数据的更有效管理。 以下是MySQL分区的…

IDEA 集成 Docker 插件一键部署 SpringBoot 应用

目录 前言IDEA 安装 Docker 插件配置 Docker 远程服务器编写 DockerFileSpringBoot 项目部署配置SpringBoot 项目部署结语 前言 随着容器化技术的崛起&#xff0c;Docker成为了现代软件开发的关键工具。在Java开发中&#xff0c;Spring Boot是一款备受青睐的框架&#xff0c;然…

PCL 半径滤波剔除噪点(二)

目录 一、算法原理二、注意事项三、代码实现一、算法原理 PCL半径滤波是删除在输入的点云一定范围内没有达到足够多领域的所有数据点。通俗的讲:就是以一个点p给定一个范围r,领域点要求的个数为m,r若在这个点的r范围内部的个数大于m则保留,小于m则删除。因此,使用该算法时…

阎良区公益创投之“小飞机大梦想” 航模DIY主题活动

创造是人类探索迈出的第一步&#xff0c;科学是开启奇妙世界的金钥匙。为进一步提升“未来星”对科技知识的兴趣&#xff0c;培养他们的科学创新精神&#xff0c;11月16日&#xff0c;阎良区社会组织公益创投——“未来星”助力乡村留守儿童成长计划项目在阎良区聚宝小学开展“…

【淘宝API】商品详情+搜索商品列表接口

淘宝商品详情API接口可以使用淘宝开放平台提供的SDK或API来获取。这些接口可以用于获取商品的详细信息&#xff0c;如标题、价格、描述、图片等。 以下是使用淘宝开放平台API获取商品详情的步骤&#xff1a; 注册淘宝开放平台账号&#xff0c;并创建应用&#xff0c;获取应用…

【具身智能评估1】具身视觉语言规划(EVLP)仿真环境汇总

参考论文&#xff1a;Core Challenges in Embodied Vision-Language Planning 论文作者&#xff1a;Jonathan Francis, Nariaki Kitamura, Felix Labelle, Xiaopeng Lu, Ingrid Navarro, Jean Oh 论文原文&#xff1a;https://arxiv.org/abs/2106.13948 论文出处&#xff1a;Jo…

C#学习相关系列之Linq常用方法---排序(一)

一、构建数据 public class Student_1{public int ID { get; set; }public string Name { get; set; }public int Chinese { get; set; }public int Math { get; set; }public int English { get; set; }public override string ToString(){return string.Format("ID:{0},…

企业视频数字人有哪些应用场景

来做个数字人吧&#xff0c;帮我干点活吧。 国内的一些数字人&#xff1a; 腾讯智影 腾讯智影数字人是一种基于人工智能技术的数字人物形象&#xff0c;具有逼真的外观、语音和行为表现&#xff0c;可以应用于各种场景&#xff0c;如新闻播报、文娱推介、营销、教育等。 幻…

医院数字化LIS(检验信息系统)源码

临床检验信息管理系统&#xff08;LIS&#xff09;是利用计算机连接医疗设备&#xff0c;通过计算机信息处理技术&#xff0c;将医院检验科或实验室的临床检验数据进行自动收集、存储、处理、提取、传输和交换&#xff0c;满足所有授权用户的功能需求。 一、系统概述 1.LIS&am…

性能测试【第三篇】Jmeter的使用

线程数:10 ,设置10个并发 Ramp-Up时间(秒):所有线程在多少时间内启动,如果设置5,那么每秒启动2个线程 循环次数:请求的重复次数,如果勾选"永远"将一直发送请求 持续时间时间:设置场景运行的时间 启动延迟:设置场景延迟启动时间 响应断言 响应断言模式匹配规则 包括…

Qt QLable 字符过长省略

前言&#xff1a; 项目中常用到字符过长问题&#xff0c;Qt默认的省略并不好用&#xff0c;不是自己想要的&#xff1b; QFontMetri 可使用 QFontMetri 当text的像素宽度超过width&#xff0c;将返回字符串的一个省略版本取决于mode。否则将返回原字符串&#xff1b; mode…

解决STM32F429烧录程序后还需复位才能植入程序的bug

1.打开魔术棒&#xff0c;打开debug 2.打开setting 3.打开Flas Download 4.开启Reset and Run 5.点进去Pack选项页面&#xff0c;去掉enable

postgresql:记录表膨胀引起的io问题的处理

文章目录 1. io异常2.查看profile报告2.1 生成事发时间段的pgprofile2.2 查看报告 3.检查table是否膨胀4.执行vacuum full5.总结 1. io异常 iostat -x 1 20 Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %rrqm %wrqm r_await w_await aqu-sz rareq…

【数据结构】直接插入排序

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;数据结构 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵 希望大佬指点一二 如果文章对你有帮助…

基于人工电场算法优化概率神经网络PNN的分类预测 - 附代码

基于人工电场算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于人工电场算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于人工电场优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…