数据结构篇四:栈

news2024/9/19 10:44:48

文章目录

  • 前言
  • 1.栈
    • 1.1 栈的概念及结构
    • 1.2 栈的实现
  • 2.栈功能的解析及实现
    • 2.1 栈的创建
    • 2.2 初始化
    • 2.3 入栈
    • 2.4 出栈
    • 2.5 检查栈是否为空
    • 2.6 获取栈顶元素
    • 2.7 栈中的有效元素个数
    • 2.8 销毁
  • 3.代码实现
    • 3.1 Stack.h
    • 3.2 Stack.c
    • 3.3 test.c
  • 4.总结

前言

  前面学习的一些结构都比较普通,今天就让我们来看一个比较特殊的结构——栈,它的特殊之处是后进先出,也就是后进来的数据先出去。

1.栈

1.1 栈的概念及结构

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

1.2 栈的实现

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

2.栈功能的解析及实现

2.1 栈的创建

  我们采用数组的形式进行实现。

typedef int DataType;
typedef struct Stack
{
	DataType* data;
	int top; //栈顶
	int capacity;容量
}Stack;

2.2 初始化

  将所有数据赋个初值。

void StackInit(Stack* ps)
{
	assert(ps);
	ps->data = NULL;
	ps->top = 0; //指向栈顶元素的下一个位置,同时也代表这栈中有多少元素
	ps->capacity = 0;//栈的容量
}

2.3 入栈

  入栈也就是要增加元素,那么首先需要做的就是判断容量够不够,不够的话就需要增容,然后再将元素放进去即可。

void StackPush(Stack* ps, DataType x)
{
	assert(ps);
	//判断是否需要增容
	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		DataType* tmp = (DataType*)realloc(ps->data,sizeof(DataType) * newcapacity);
		if (tmp == NULL)
		{
			return;
		}
		ps->data = tmp;
		ps->capacity = newcapacity;
	}
	ps->data[ps->top] = x;
	ps->top++;
}

2.4 出栈

  出栈的话我们只能从栈顶出元素,不能从其他位置出。既然要删除元素,那么我们就需要判断栈中是否还有剩余元素,没有的话就不需要删除。这里我写了一种方式,不过后面还会写一个判断栈是否为空的函数,大家看个人喜好采用。

void StackPop(Stack* ps)
{
	assert(ps);
	//assert(ps->top > 0);
	assert(!StackEmpty(ps));
	ps->top--;
}

2.5 检查栈是否为空

  写的比较简洁,返回的是ps->top == 0,也就是如果条件成立,这个表达式就代表着true(也就是栈为空),如果不成立就代表着false(栈不为空)。

bool StackEmpty(Stack* ps)
{
	assert(ps);
	return ps->top == 0;
}

2.6 获取栈顶元素

  我们的top指向的是栈顶元素的下一个位置,所以在数组中最后一个元素也就是栈顶的元素位置是top - 1。

DataType StackTop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));//判断是否为空
	return ps->data[ps->top - 1];
}

2.7 栈中的有效元素个数

  在创建栈哪里就提到了,top既指向栈顶元素的后一个位置,也代表着栈中的元素个数。

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

2.8 销毁

  动态开辟的空间在程序结束时都需要被回收,用来防止出现内存泄漏。

void StackDestroy(Stack* ps)
{
	ps->top = 0;
	ps->capacity = 0;
	free(ps->data);
	ps->data = NULL;
}

3.代码实现

3.1 Stack.h

   栈的创建以及各个函数声明。

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
#include<stdlib.h>
typedef int DataType;
typedef struct Stack
{
	DataType* data;
	int top;
	int capacity;
}Stack;

// 初始化栈
void StackInit(Stack* ps);

// 入栈
void StackPush(Stack* ps, DataType x);

// 出栈
void StackPop(Stack* ps);

// 获取栈顶元素
DataType StackTop(Stack* ps);

// 获取栈中有效元素个数
int StackSize(Stack* ps);

// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty(Stack* ps);

// 销毁栈
void StackDestroy(Stack* ps);

3.2 Stack.c

  栈的各功能的函数。

#include"Stack.h"

void StackInit(Stack* ps)
{
	assert(ps);
	/*DataType* tmp = (DataType*)malloc(sizeof(DataType));
	if (tmp == NULL)
	{
		return;
	}*/

	ps->data = NULL;
	ps->top = 0;      //指向栈顶元素的下一个位置,同时也代表这栈中有多少元素
	ps->capacity = 0;
}

void StackPush(Stack* ps, DataType x)
{
	assert(ps);
	//判断是否需要增容
	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		DataType* tmp = (DataType*)realloc(ps->data,sizeof(DataType) * newcapacity);
		if (tmp == NULL)
		{
			return;
		}
		ps->data = tmp;
		ps->capacity = newcapacity;
	}
	ps->data[ps->top] = x;
	ps->top++;
}

bool StackEmpty(Stack* ps)
{
	assert(ps);
	return ps->top == 0;
}

void StackPop(Stack* ps)
{
	assert(ps);
	//assert(ps->top > 0);
	assert(!StackEmpty(ps));
	ps->top--;
}

DataType StackTop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));
	return ps->data[ps->top - 1];
}

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

void StackDestroy(Stack* ps)
{
	ps->top = 0;
	ps->capacity = 0;
	free(ps->data);
	ps->data = NULL;
}

3.3 test.c

  用来测试实现的栈功能有没有问题。

#include"Stack.h"

void test()
{
	Stack st;
	StackInit(&st);//初始化

	StackPush(&st, 1);//测试:入栈
	StackPush(&st, 2);
	StackPush(&st, 3);
	StackPush(&st, 4);
	while(!StackEmpty(&st))
	{
		printf("%d ", StackTop(&st));
		StackPop(&st);
	}
	printf("\n");


	StackPush(&st, 5);//入栈一些元素进行测试
	StackPush(&st, 6);

	StackPop(&st);//测试:中途出栈的效果,实际就是将6提前出栈

	StackPush(&st, 7);
	StackPush(&st, 8);
	while (!StackEmpty(&st))
	{
		printf("%d ", StackTop(&st));
		StackPop(&st);
	}
	printf("\n");


	StackPush(&st, 1);//入栈一些数据进行测试
	StackPush(&st, 2);
	StackPush(&st, 3);
	StackPush(&st, 4);

	int sz = StackSize(&st);//测试:计算栈中元素个数
	printf("%d\n", sz);

	StackDestroy(&st);
}
int main()
{
	test();
	return 0;
}

4.总结

  单纯从代码实现角度来看,栈的实现还是比较简单的,因此可以不用在代码实现方面下太大的功夫,将更多的注意力转移到做题方面,感觉会有更好的效率性。
  栈的讲解就先告一段落了,如果发现文章哪里有问题可以在评论区提出来或者私信我嗷。接下来我会继续深入学习数据结构的其他知识,开启新的篇章,那么本期就到此结束,让我们下期再见!!觉得不错可以点个赞以示鼓励喔!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

13 | visual studio与Qt的结合

1 前提 Qt 5.15.2 visual studio 2019 vsaddin 2.8 2 具体操作 2.1 visual studio tool 2.1.1 下载 https://visualstudio.microsoft.com/zh-hans/downloads/2.1.2 安装 开发

推荐算法实战项目:WideDeep原理以及案例实战(附完整 Python 代码)

本文要介绍的是Google于2016年提出的Wide&Deep模型&#xff0c;此模型的提出对业界产生了非常大的影响&#xff0c;不仅其本身成功地应用在多家一线互联网公司&#xff0c;而且其后续的改进工作也一直延续至今。 Wide&Deep模型正如其名&#xff0c;分别包含了Wide部分…

golang - 函数的使用

核心化编程 为什么需要函数&#xff1f; 代码冗余问题不利于代码维护函数可以解决这个问题 函数 函数&#xff1a;为完成某一功能的程序指令&#xff08;语句&#xff09;的集合&#xff0c;称为函数 在 Go 中&#xff0c;函数分为&#xff1a;自定义函数&#xff08;自己写…

Apache Solr Velocity模板注入RCE

Apache Solr Velocity模板注入RCE 一、Apache Solr介绍 Solr是一个独立的企业级搜索应用服务器,它对外提供类似于web-service的API接口,用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引,也可以通过http get操作提出查找请求,并得到XML格式的返回结果。…

【openFrameworks】跨平台的 C++ 开源框架 | oF 文件结构 | 图形基础介绍

&#x1f4ad; 写在前面&#xff1a;本章我们将介绍一个非常好用的跨平台的 C 开源框架 —— openFrameworks。它是一个开源的跨平台的 C工具包&#xff0c;方便开发者创建出一个更简单和直观的框架&#xff0c;擅长开发图像和动画。 &#x1f4dc; 本章目录&#xff1a; 0x0…

SpringBoot集成SpringSecurity从0到1搭建权限管理详细过程(认证+授权)

前言 最近工作需要给一个老系统搭建一套权限管理&#xff0c;选用的安全框架是SpringSecurity&#xff0c;基本上是结合业务从0到1搭建了一套权限管理&#xff0c;然后想着可以将一些核心逻辑抽取出来写一个权限通用Demo&#xff0c;特此记录下。 文章目录 前言1、SpringSecuri…

CSS中4个定位设计与实现

1.相对定位 说明&#xff1a;相对原来元素的定位。开启定位后&#xff0c;元素层级高&#xff0c;会置于最上层 作用&#xff1a;用于元素的微调&#xff0c;不会脱离文档流 1.1代码实现 <!DOCTYPE html> <html lang"zh"> <head><meta charset…

外卖项目优化-01-redis缓存短信验证码、菜品数据、Spring Cache(注解开发缓存)、(注解开发)缓存套餐数据

文章目录 外卖项目优化-01课程内容前言1. 环境搭建1.1 版本控制解决branch和tag命名冲突 1.2 环境准备 2. 缓存短信验证码2.1 思路分析2.2 代码改造2.3 功能测试 3. 缓存菜品信息3.1 实现思路3.2 代码改造3.2.1 查询菜品缓存3.2.2 清理菜品缓存 3.3 功能测试3.4 提交并推送代码…

每日一题133——环形链表

给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&#xff08;…

5. 操作系统基础

5. 操作系统基础 常考面试题 说说你对进程的理解⭐⭐⭐ 程序是指令、数据及其组织形式的描述,而进程则是程序的运行实例,包括程序计数器、寄存器和变量的当前值。 Linux的进程结构,一般分为三部分:代码段、数据段(.data与.bss)和堆栈段。 代码段用于存放程序代码,如果有…

【计算机图形学基础教程】面向对象程序设计基础

构造函数与析构函数 例1 设计一个长方形CRectangle类&#xff0c;调用类的成员函数计算长方形的周长和面积。 #include <iostream>class CRectangle { public:CRectangle(); // 声明默认构造函数CRectangle(int width, int height); // 声明带…

Python基础合集 练习21 (错误与异常处理语句)

‘’‘try: block1 except[ExceptionName]: block2 ‘’’ block1:执行代码,表示可能会出现错误的代码块 ExceptionName: 表示要捕获的异常名称,为可选参数.如果不指定异常名称,则表示捕获所有异常 block2:表示发生异常时执行的代码块 while True: try: num int(input(请输…

测试时,可快速调用 Mapper 的 Mapper Generator

项目 Gitee 地址&#xff1a;MapperGenerator (当前使用的是 JDK17&#xff0c;JDK8 的需改下 pom.xml 文件&#xff09; 解决的问题&#xff1a;SpringBootTest 启动太慢 使用方式 假设有这样一个数据库&#xff0c;名为 a SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;…

推荐 3 个令你惊艳的 GitHub 项目

昨日 GitHub Trending 上榜的开源项目&#xff0c;基于 AI 技术提高你的生产力。借助 AI 你能搭建自己的数字人、搭建自己的法律助手、文档分析助手。 本期推荐开源项目目录&#xff1a; 1. 数字人开源项目 2. AI 法律助手 3. 为 PDF 文档打招一个聊天机器人 01 数字人开源项目…

作业区域工服穿戴识别算法 yolov7

作业区域工服穿戴识别系统基于yolov7视频智能图像识别技术&#xff0c;作业区域工服穿戴识别算法模型利用深度学习技术&#xff0c;不需人为干预自动识别现场施工作业人员未按要求穿工作服行为&#xff0c;代替后台工作人员执勤时的人眼判断。YOLOv7 研究团队提出了基于 ELAN 的…

win10 全屏秒退

问题 程序比较老&#xff0c;而电脑配置很新窗口化无任何问题&#xff0c;但是一旦全屏就退出 解决方案 猜测可能是兼容性的问题。 定位发现&#xff1a;禁用全屏优化。 方式如下&#xff1a;右键配置。选择兼容性。 选择禁用全屏优化。以兼容性运行这个程序。

什么是图数据库Neo4j

什么是图数据库Neo4j 所谓的图数据库一般由节点和关系构成&#xff0c;neo4j是其中的一种 在寻求数据的关联性中优于传统数据库mysql 且neo4j支持上亿级别的节点和关系 传统图运算一般在内存中进行&#xff0c;无法处理整个知识图谱&#xff0c;neo4j可以在磁盘中完成图运算…

【官网解读】主页解读

1.简况 Quick Prototyping&#xff08;快速原型设计&#xff09; Build machine learning solutions on raw data&#xff08;原始数据&#xff09; in a few lines of code. State-of-the-art Techniques&#xff08;最先进的技术&#xff09; Automatically utilize SOTA…

如何进行物联网渗透测试?

渗透测试揭示了未知的安全漏洞&#xff0c;因为值得信赖的专业人员模拟威胁性攻击。他们深入挖掘固件和硬件&#xff0c;以查找漏洞和可访问性疏忽。 物联网(IoT)连接设备是严重且可预防的安全漏洞的意外来源&#xff0c;现在是时候像其他硬件一样对其进行渗透测试处理了。为什…

疑难问题定位案例复盘(二)

今天我们继续分析一个因野指针访问导致的内存异常、出现coredump问题。在上一篇案例中&#xff0c;我们分享了一个在内存被释放后&#xff0c;业务模块仍然在使用导致业务模块自身出现coredump的现象。其实&#xff0c;在使用野指针访问内存时还有一种可能&#xff0c;就是业务…