手撕数据结构 —— 栈(C语言讲解)

news2025/2/23 2:22:40

目录

1.认识栈

什么是栈

栈的示意图

2.如何实现栈

3.栈的实现

Stack.h中接口总览

具体实现

结构的定义

初始化栈

销毁栈

入栈

出栈

取栈顶元素

获取有效元素的个数

判断栈是否为空

4.完整代码附录

Stack.h

Stack.c


1.认识栈

什么是栈

栈是一种特殊的线性表,只允许在固定的一端进行数据的插入和删除操作;

  • 进行数据的插入和删除的一端叫做栈顶,另一端叫做栈底。
  • 栈中的数据必须严格遵守后进先出的原则,这也是栈这种数据结构最重要的特点。

栈的示意图

两个专业术语:

  • 入栈:栈的插入数据元素的操作叫做入栈。

  • 出栈:栈的删除数据元素的操作叫做出栈。

入栈和出栈都是在栈顶进行的。

2.如何实现栈

要想实现栈,必须满足以下两个条件:

  • a、控制在一端进行数据的插入和删除
  • b、满足后进先出的原则。

基于上述条件,我们可以使用数组或者链表来实现栈,那么使用哪种数据结构来实现栈更好呢?

我们可以对比一下:

数组(顺序表)链表(单链表)
头插效率O(N)O(1)
头删效率O(N)O(1)
尾插效率O(1)O(N)
尾删效率O(1)O(N)

可以看出,使用数组(顺序表)来实现栈的话,需要将尾部作为栈顶,插入数据和删除数据的时间复杂度都是O(1)。使用链表(单链表)来实现栈的话,需要将头部作为栈顶,插入数据和删除数据的时间复杂度都是O(1)。

但是相对而言,使用数组实现栈更优,因为数组没有太多的指针操作,删除数据的时候只需要让size-- 即可(size是数组中有效元素的个数),插入数据的时候直接赋值即可。

我们实现栈的时候,采用数组的形式实现数组栈。

3.栈的实现

实现栈的时候,我们主要实现Stack.h 和 Stack.c这两个文件,Stack.h用来存放声明,Stack.c用来存放定义。

Stack.h中接口总览

具体实现

结构的定义

因为静态的栈不实用,我们实现的数组栈采用动态增长的形式。

  • a指向动态开辟的内存空间的起始地址。
  • top指向栈顶元素的下一个位置。
  • capacity表示栈的容量,当容量不够的时候,需要动态扩容。

初始化栈

初始化栈的之后,将a置为空,capacity和top都为0。

  • top初始化为0表示top指向栈顶元素的下一个位置。
  • top如果初始化为-1表示top指向栈顶元素。
  • 两种方式实现都可以,我们采用第一种,这样的好处是top的值直接就可以表示栈中数据元素的个数。

注意:指向物理空间的指针ps不能为空,后面涉及该指针变量的地方都一样。

销毁栈

销毁栈的时候,只需要将动态申请的空间释放,并将指向这块空间的指针置空;然后将top和capacity都置为0即可。

入栈

实现入栈需要注意以下几个点:

  • 栈空间不能为空,使用断言assert()暴力判断。
  • 注意空间是否足够,空间不够时需要扩容。
  • 元素入栈之后,top记得++。

出栈

出栈时需要注意以下几点:

  • 指向物理空间的指针不能为空。
  • 栈中元素个数 >0 时元素才能出栈。
  • 元素出栈之后记得将top-- 。 

取栈顶元素

我们定义结构的时候,将top定义为栈顶元素的下一个位置,top-1就表示栈顶元素的下标,直接返回栈顶元素即可。

获取有效元素的个数

top也能表示栈中有效元素的个数,直接返回top即可。

判断栈是否为空

top表示栈中有效数据的个数,当top == 0时,栈为空;当top != 0时,栈不为空。

4.完整代码附录

Stack.h

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;    // 指向动态开辟的顺序表 
	int top;          // 指向栈顶元素的下一个位置 
	int capacity;     // 表示栈的容量 
}ST;

void STInit(ST* ps);                 // 初始化栈 
void STDestroy(ST* ps);              // 销毁栈 
void STPush(ST* ps, STDataType x);   // 入栈 
void STPop(ST* ps);                  // 出栈 
STDataType STTop(ST* ps);            // 取栈顶元素 
int STSize(ST* ps);                  // 获取有效元素的个数 
bool STEmpty(ST* ps);                // 判断栈是否为空 

Stack.c

#include "Stack.h"

void STInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

void STDestroy(ST* ps)
{
	assert(ps);

	free(ps->a);
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

void STPush(ST* ps, STDataType x)
{
	assert(ps);

	if (ps->top == ps->capacity)     // 当 top==capacity时就需要扩容了  
	{
		// 初始空间为4,扩容按照两倍扩 
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		
		// 当a为空的时候,realloc的功能类似于malloc 
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
		
		if (tmp == NULL)             // 判断扩容是否成功 
		{
			perror("realloc fail");
			exit(-1);
		}

		ps->a = tmp;                 // 将开辟的空间赋值给变量a 
		ps->capacity = newCapacity;  // 更新容量 
	}

	ps->a[ps->top] = x;              // 元素入栈 
	ps->top++;                       // top++指向栈顶元素的下一个位置 
}


void STPop(ST* ps)
{
	assert(ps);          // 指针不能为空 

	assert(ps->top > 0); // 栈中元素个数 >0 元素才能出栈 

	--ps->top;           // 元素出栈之后记得将top-- 
}

STDataType STTop(ST* ps)
{
	assert(ps);            
 
	assert(ps->top > 0);        // 栈中有元素 

	return ps->a[ps->top - 1];  // 返回栈顶元素 
}

int STSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

bool STEmpty(ST* ps)
{
	assert(ps);

	return ps->top == 0;
}

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

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

相关文章

【动物识别系统】Python+卷积神经网络算法+人工智能+深度学习+机器学习+计算机课设项目+Django网页界面

一、介绍 动物识别系统。本项目以Python作为主要编程语言&#xff0c;并基于TensorFlow搭建ResNet50卷积神经网络算法模型&#xff0c;通过收集4种常见的动物图像数据集&#xff08;猫、狗、鸡、马&#xff09;然后进行模型训练&#xff0c;得到一个识别精度较高的模型文件&am…

DS线性表之单链表的讲解和实现(2)

文章目录 前言一、链表的概念二、链表的分类三、链表的结构四、前置知识准备五、单链表的模拟实现定义头节点初始化单链表销毁单链表打印单链表申请节点头插数据尾插数据头删数据尾删数据查询数据在pos位置之后插入数据删除pos位置之后的数据 总结 前言 本篇的单链表完全来说是…

使用PyTorch从0实现Fashion-MNIST数据集分类

完整代码&#xff1a; from d2l import torch as d2l import torch from torchvision import transforms from torchvision import datasets from torch.utils.data import DataLoader import matplotlib.pyplot as plt from IPython import displaydef get_fashion_mnist_la…

BBR 的不公平性

BBR 公平收敛在相图中的细节 和 aimd&#xff0c;bbr&#xff0c;inflt 守恒的收敛相图总结 已经介绍了 BBR 的 gain 不公平性&#xff0c;本文介绍 BBR 的 RTT 不公平性。 直觉上&#xff0c;BBR 采用 probe_quota gain * maxbw * minrtt 来 probe 带宽&#xff0c;minrtt 越…

掌握Postman,开启API测试新纪元!

Postman是一款流行的API测试工具和开发环境&#xff0c;旨在简化API开发过程、测试和文档编制。它提供了一套功能强大的工具&#xff0c;帮助开发人员更轻松地构建、测试和调试Web服务。 Postman 工具的优势 Postman 可以快速构建请求、还可以保存以后再使用。 Postman 还提…

改进系列:TransUnet结合SAM box改进对MICCAI FLARE腹部13器官图像分割

目录 1、前言 2、实现思路 3、实验代码 3.1 环境配置 3.2 数据集 3.3 训练 3.4 指标 3.5 推理 4、其他 1、前言 本章尝试将TransUnet和SAM结合&#xff0c;以期望达到更换的模型 TransUnet作为医学图像分割的基准&#xff0c;在许多数据集上均取得了很好的效果&#x…

JavaSE——认识异常

1.概念 在生活中&#xff0c;人有时会生病&#xff0c;在程序中也是一样&#xff0c;程序猿是一帮办事严谨、追求完美的高科技人才。在日常开发中&#xff0c;绞尽脑汁将代码写的尽善尽美&#xff0c;在程序运行过程中&#xff0c;难免会出现一些奇奇怪怪的问题。有时通过代码很…

2024/10/12 计组大题专训

2018&#xff1a; 2019&#xff1a; 2020&#xff1a; 2021&#xff1a;

【多线程】多线程(12):多线程环境下使用哈希表

【多线程环境下使用哈希表&#xff08;重点掌握&#xff09;】 可以使用类&#xff1a;“ConcurrentHashMap” ★ConcurrentHashMap对比HashMap和Hashtable的优化点 1.优化了锁的粒度【最核心】 //Hashtable的加锁&#xff0c;就是直接给put&#xff0c;get等方法加上synch…

AI+若依框架day02

项目实战 项目介绍 帝可得是什么 角色和功能 页面原型 库表设计 初始AI AIGC 提示工程 Prompt的组成 Prompt练习 项目搭建 点位管理 需求说明 库表设计

多线程学习篇四:synchronized

1. synchronized 的使用 1.1 作用于实例方法 Slf4j(topic "c.Test01") public class Test01 {public synchronized void method1() {// 代码逻辑} } 等价于下列写法&#xff1a; Slf4j(topic "c.Test01") public class Test01 {public void method1…

基于机器学习的虚假新闻智能检测系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 随着互联网的普及和社交媒体的发展&#xff0c;虚假新闻&#xff08;fake news&#xff09;问题日益严重&#xff0c;对社会和个人产生了诸多负面影响。传统的新闻审核方法通常依赖于人工审核&…

基于gewechat制作第一个微信聊天机器人

Gewe 个微框架 GeWe&#xff08;个微框架&#xff09;是一个创新性的软件开发框架&#xff0c;为个人微信号以及企业信息安全提供了强大的功能和保障。GeWe的设计旨在简化开发过程&#xff0c;使开发者能够高效、灵活地构建和定制通信协议&#xff0c;以满足不同应用场景的需求…

SSL---SSL certificate problem

0 Preface/Foreword 0.1 SSL certificate problem 开发过程中&#xff0c;gitlab-runner连接gitlab时候出现SSL 证书问题。 场景&#xff1a;公司的gitlab runner服务器引入了SSL证书&#xff0c;每年都会主动更新一次。当前的gitlab-runner运行在PC机器上&#xff0c;但是g…

ZYNQ使用XGPIO驱动外设模块(前半部分)

目录 目录 一、新建BD文档&#xff0c;添加ZYNQ处理器 1.BD文档: 2.在Vivado中&#xff0c;BD文件的生成过程通常包括以下步骤&#xff1a; 1)什么是Tcl Console: 3.PL部分是FPGA可编程逻辑部分&#xff0c;它提供了丰富的IO资源&#xff0c;可以用于实现各种硬件接口和功…

刘文超数量关系笔记

第一章解题技巧 第一节代入排除法 代入排除是数量关系第一大法。 代入排除顾名思义是将答案选项代入原题目&#xff0c;与题意不符的选项即可排除&#xff0c; 最终得出正确答案。 优先使用代入排除的题型&#xff1a; &#xff08;1&#xff09;多位数问题、余数问题、年龄…

node.js服务器基础

node.js的事件循环 node.js是基于事件驱动的&#xff0c;通常在代码中注册想要等待的事件&#xff0c;设定好回调函数&#xff0c;当事件触发的时候就会调用回调函数。如果node.js没有要处理的事件了&#xff0c;那整个就结束了;事件里面可以继续插入事件&#xff0c;如果有事…

【2021】知识图谱导论(陈华钧)——阅读思考与笔记

tips&#xff1a;其中所有【】表示的内容为博主本人想法&#xff0c;非作者观点&#xff0c;请注意辨别。 这是一本全面覆盖知识图谱多个方面的书籍。书中不仅详细介绍了知识图谱的表示、存储、获取、推理、融合、问答和分析等七大方面&#xff0c;还深入探讨了多模态知识图谱…

【Nginx系列】Nginx启动失败

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

[⑦5G NR]: PSS/SSS同步信号学习

在5G中&#xff0c;PSS(Primary Synchronization Signal) 主同步信号和SSS(Secondary Synchronization Signal)辅同步信号是用于物理层的信号&#xff0c;用于小区的搜索。 PSS 跟据协议38.211 7.4.2.2章节&#xff0c;PSS是3条长度为127的m序列&#xff0c;分别对应 N I D (…