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

目录

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.mzph.cn/diannao/56021.shtml

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

相关文章

创建XGBoost模型(回归任务)MATLAB

代码如下&#xff1a; % 导入数据 data readtable(data.xlsx);% 假设最后一列是目标值&#xff0c;前面列为特征 X data{:, 1:end-1}; % 特征 y data{:, end}; % 目标值% 划分训练集和测试集 cv cvpartition(height(data), HoldOut, 0.2); XTrain X(training(cv)…

最懂生活的年轻人,都在喝十元奶茶

文 | 螳螂观察 作者 | 如意 以前的打工人&#xff0c;总把二三十的高价奶茶当成身份的象征&#xff0c;喝上了高价奶茶才能叫做在生活中富养自己。 只是&#xff0c;到盘开支的时候&#xff0c;打工人才猛然发觉&#xff0c;动辄二三十一杯的奶茶&#xff0c;不知不觉刮走了…

美团测试面试真题学习

美团真题1–测试基础-业务场景说下你的测试用例设计 功能角度 方法论 边界值、等价类划分、错误推测法示例 输入已注册的用户名和正确的密码&#xff0c;验证是否登录成功;输入已注册的用户名和不正确的密码&#xff0c;验证是否登录失败输入未注册的用户名和任意密码&#xff…

RabbitMQ事务模块

目录 消息分发​​​​​​​ 负载均衡 幂等性保障 顺序性保障 顺序性保障方案 二号策略:分区消费 三号策略:消息确认机制 四号策略: 消息积压 RabbitMQ集群 选举过程 RabbitMQ是基于AMQP协议实现的,该协议实现了事务机制&#xff0c;要么全部成功&#xff0c;要么全…

网站在对抗机器人攻击的斗争中失败了

95% 的高级机器人攻击都未被发现&#xff0c;这一发现表明当前的检测和缓解策略存在缺陷。 这表明&#xff0c;虽然一些组织可能拥有基本的防御能力&#xff0c;但他们没有足够的能力应对更复杂的攻击。 例如利用人工智能和机器学习来模仿人类行为的攻击。 这些统计数据强调…

反转链表解题思路

题目描述 给定一个单链表的头结点pHead&#xff0c;长度为n&#xff0c;反转该链表后&#xff0c;返回新链表的表头。 示例&#xff1a;当输入链表{1,2,3}时&#xff0c;经反转后&#xff0c;原链表变为{3,2,1}&#xff0c;所以对应的输出为{3,2,1}。 解题思路&#xff1a;迭…

VMDK 0X80BB0005 VirtualBOX虚拟机错误处理-数据恢复——未来之窗数据恢复

打开虚拟盘文件in7.vmdk 失败. Could not get the storage format of the medium 7\win7.vmdk (VERR_NOT_SUPPORTED). 返回 代码:VBOX_E_IPRT_ERROR (0X80BB0005) 组件:MediumWrap 界面:IMedium {a a3f2dfb1} 被召者:IVirtualBox {768 cd607} 被召者 RC:VBOX_E_OBJECT_NOT_F…

JavaScript(Web APIs 作用和分类,DOM数是什么,document是什么,根据css选择器来获取DOM元素,修改DOM元素的方式,边量声明)

变量声明 变量声明有三个 var let 和 const建议&#xff1a; const 优先&#xff0c;尽量使用const&#xff0c;原因是&#xff1a; const 语义化更好 很多变量我们声明的时候就知道他不会被更改了&#xff0c;那为什么不用 const呢&#xff1f; 实际开发中也是&#xff0c;…

IDE启动失败

报错&#xff1a;Cannot connect to already running IDE instance. Exception: Process 24,264 is still running 翻译&#xff1a;无法连接到已运行的IDE实例。异常:进程24,264仍在运行 打开任务管理器&#xff0c;找到PID为24264的CPU线程&#xff0c;强行结束即可。 【Ct…

JavaScript进阶笔记--深入对象-内置构造函数及案例

深入对象 创建对象三种方式 利用对象字面量new Object&#xff08;{…}&#xff09;利用构造函数 // 1. 字面量创建对象const obj1 {name: pig,age: 18};console.log(obj1); // {name: "pig", age: 18}// 2. 构造函数创建对象function Pig(name, age) {this.name…

聚类分析 | AP近邻传播聚类算法

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 AP近邻传播聚类算法 AP&#xff08;Affinity Propagation&#xff09;近邻传播聚类算法是一种基于数据点之间的相似度矩阵来进行聚类的算法。该算法不需要事先设定聚类簇的个数&#xff0c;而是通过在数据点之间传播…

GAN(Generative Adversarial Nets)

GAN(Generative Adversarial Nets) 引言 GAN由Ian J. Goodfellow等人提出&#xff0c;是Ian J. Goodfellow的代表作之一&#xff0c;他还出版了大家耳熟能详的花书&#xff08;Deep Learning深度学习&#xff09;&#xff0c;GAN主要的思想是同时训练两个模型&#xff0c;生成…

根据请求错误的状态码判断代理配置问题

SafeLine&#xff0c;中文名 “雷池”&#xff0c;是一款简单好用, 效果突出的 Web 应用防火墙(WAF)&#xff0c;可以保护 Web 服务不受黑客攻击。 雷池通过过滤和监控 Web 应用与互联网之间的 HTTP 流量来保护 Web 服务。可以保护 Web 服务免受 SQL 注入、XSS、 代码注入、命…

【面试宝典】深入Python高级:直戳痛点的题目演示(下)

目录 &#x1f354; Python下多线程的限制以及多进程中传递参数的⽅式 &#x1f354; Python是如何进⾏内存管理的&#xff1f; &#x1f354; Python⾥⾯如何拷⻉⼀个对象&#xff1f; &#x1f354; Python⾥⾯search()和match()的区别&#xff1f; &#x1f354; lambd…

力扣LeetCode-链表中的循环与递归使用

标题做题的时候发现循环与递归的使用差别&#xff1a; 看两道题&#xff1a; 两道题都是不知道链表有多长&#xff0c;所以需要用到循环&#xff0c;用到循环就可以把整个过程分成多个循环体&#xff0c;就是每一次循环要执行的内容。 反转链表&#xff1a; 把null–>1…

springboot 整合 rabbitMQ(1)

目录 一、MQ概述 二、MQ的优势和劣势 三、常见的MQ产品 RabbitMQ使用步骤 第一步&#xff1a;确保rabbitmq启动并且可以访问15672 第二步&#xff1a;导入依赖 第三步&#xff1a;配置 auto自动确认 manual手工确认&#xff08;推荐使用&#xff01;可以防止消息丢失&a…

数字电路尚硅谷学习笔记

学习视频&#xff1a;01_数字电路_从零搭建计算机引导_哔哩哔哩_bilibili 第1章数字电路基础 1.引言 数字电路是现代科技和工程领域中不可或缺的基础。从计算机系统到通信设备&#xff0c;从家庭电子产品到工业自动化&#xff0c;数字电路无处不在&#xff0c;影响着我们的生…

Ubuntu 22.04 安装 KVM

首先检查是否支持 CPU 虚拟化&#xff0c;现在的 CPU 都应该支持&#xff0c;运行下面的命令&#xff0c;大于0 就是支持。 egrep -c (vmx|svm) /proc/cpuinfo安装 Libvirt apt install -y qemu-kvm virt-manager libvirt-daemon-system virtinst libvirt-clients bridge-uti…

华为FreeBuds 6i戴久了会耳朵胀痛吗?该怎么办?

华为FreeBuds 6i戴久了&#xff0c;会有耳朵胀痛的感觉吗&#xff1f;其实可能是没选对适合自己的耳塞&#xff0c;给你们分享几个佩戴更舒服的方法&#xff0c;一起来看看~ 首先和大家说说为什么华为FreeBuds 6i戴久了不舒服&#xff0c;一方面是耳塞尺寸不合适&#xff0c;另…

数据结构-5.5.二叉树的存储结构

一.二叉树的顺序存储&#xff1a; a.完全二叉树&#xff1a; 1.顺序存储中利用了静态数组&#xff0c;空间大小有限&#xff1a; 2.基本操作&#xff1a; (i是结点编号) 1.上述图片中i所在的层次后面的公式应该把n换成i(图片里写错了)&#xff1b; 2.上述图片判断i是否有左…