数据结构-如何巧妙实现一个栈?逐步解析与代码示例

文章目录

  • 引言
  • 1.栈的基本概念
  • 2.选择数组还是链表?
  • 3. 定义栈结构
  • 4.初始化栈
  • 5.压栈操作
  • 6.弹栈操作
  • 7.查看栈顶和判断栈空
  • 9.销毁栈操作
  • 10.测试并且打印栈内容
  • 栈的实际应用
  • 结论

引言

栈是一种基本但强大的数据结构,它在许多算法和系统功能中扮演着关键角色。在这篇文章中,我们将深入探讨如何在实现一个栈,从基本概念到具体的代码实现,再到实际应用场景的探讨。

1.栈的基本概念

在深入代码之前,先简单介绍栈的概念。栈是一个项的有序集合,其中添加(推入)和删除(弹出)项总发生在同一端,称为“栈顶”。他是后进先出的,就好像弹夹里面的子弹一样

在这里插入图片描述
在这里插入图片描述

2.选择数组还是链表?

数组的优点在于实现简单,访问时间快。但其缺点是大小固定,可能会有空间浪费或不足的问题。
链表的优点在于可以动态调整大小,内存利用率高。但其缺点是相对于数组,访问时间可能会稍慢。
我们用数组来实现
在这里插入图片描述


3. 定义栈结构

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>

typedef int STDataType;
typedef struct Stack
{
  STDataType* a;
  STDataType top; 
  STDataType capacity;
}ST;

接口

void STInit(ST* pst);
void STDestroy(ST* pst);
void STPush(ST* pst,STDataType x);
void STPop(ST* pst);
STDataType STTop(ST* pst);
bool STEmpty(ST* pst);
int STSize(ST* pst);

4.初始化栈

初始化是栈实现中的第一步。我们需要将栈顶 top 的初始值设为0,以表示栈为空,在这个实现中,栈被定义为包含动态数组、栈顶指针和容量的结构体。初始化函数 STInit 负责设置这些属性的初始状态。

// 初始化栈
void STInit(ST* pst)
{
  assert(pst);
  pst->a = NULL;       // 初始时,数组指针为空
  pst->top = 0;        // 栈顶指针初始为0,表示栈为空
  pst->capacity = 0;   // 初始容量为0
}

5.压栈操作

在实现压栈操作时,我们要考虑栈可能满的情况。如果栈已满,我们应该阻止进一步的压栈并给出适当的反馈。

// 检查并扩展栈的容量
void SLCheckCapacity(ST* pst)
{
  assert(pst);
  if (pst->top == pst->capacity)
  {
    int newCapacity = (pst->capacity == 0) ? 4 : pst->capacity * 2;
    STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newCapacity);
    if (tmp == NULL)
    {
      perror("realloc fail");
      exit(1); // 如果内存分配失败,则退出程序
    }

    pst->a = tmp;
    pst->capacity = newCapacity;
  }
}

// 向栈中推入一个元素
void STPush(ST* pst, STDataType x)
{
  assert(pst);
  SLCheckCapacity(pst); // 检查并扩展容量
  pst->a[pst->top] = x; // 存放元素
  pst->top++;           // 栈顶指针增加
}

6.弹栈操作

弹栈时,我们需要确保栈不为空。如果尝试从空栈中弹出元素,应该返回一个错误指示。

// 从栈中弹出一个元素
void STPop(ST* pst)
{
  assert(pst);
  assert(pst->top > 0); // 确保栈不为空
  pst->top--;           // 栈顶指针减少
}

7.查看栈顶和判断栈空

这些操作相对简单,但它们对于栈的有效使用至关重要。

// 获取栈顶元素
STDataType STTop(ST* pst)
{
  assert(pst);
  assert(pst->top > 0); // 确保栈不为空
  return pst->a[pst->top - 1]; // 返回栈顶元素
}

// 检查栈是否为空
bool STEmpty(ST* pst)
{
  assert(pst);
  return pst->top == 0; // 如果栈顶指针为0,则栈为空
}

9.销毁栈操作

在这个静态数组实现中,destroy 函数不是必须的,但是我们使用了动态分配的内存,则需要在此释放内存。

// 销毁栈
void STDestroy(ST* pst)
{
  assert(pst);
  free(pst->a);        // 释放栈内部的数组空间
  pst->a = NULL;       // 将数组指针置为空
  pst->top = 0;        // 栈顶指针重置为0
  pst->capacity = 0;   // 容量重置为0
}

10.测试并且打印栈内容

int main()
{
  ST stack;            // 定义栈变量
  ST* pst = &stack;    // pst 指向 stack
  STInit(pst);         // 初始化栈

  // 向栈中添加元素
  STPush(pst, 1);
  STPush(pst, 2);
  STPush(pst, 3);
  STPush(pst, 4);

  // 打印并弹出栈中的元素
  while (!STEmpty(pst))
  {
    printf("%d ", STTop(pst));
    STPop(pst);
  }
  printf("\n");

  STDestroy(pst); // 销毁栈
  return 0;
}

运行结果如下:
在这里插入图片描述


栈的实际应用

栈在计算机科学中有着广泛的应用。从函数调用的内存管理到算法中的临时数据存储,栈的应用无处不在。理解栈如何在这些场景中工作,对于充分利用其潜力至关重要。


结论

栈不仅是一种基本的数据结构,而且是理解更复杂系统和算法的基石。通过在c语言中实现和应用栈,我们不仅能够加深对这一结构的理解,还能够提高我们的编程技巧和问题解决能力。我希望这篇文章能够帮助你更好地理解和实现栈。如果你有任何问题或想分享你的经验,请在评论区留言。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android UID相关知识

一、UID/PID/GID/GIDS的含义和作用 UID : android中uid用于标识一个应用程序&#xff0c;uid在应用安装时被分配&#xff0c;并且在应用存在于手机上期间&#xff0c;都不会改变。一个应用程序只能有一个uid&#xff0c;多个应用可以使用sharedUserId 方式共享同一个uid&#…

Torchvision中的Transforms的使用

一、transforms结构及用法 查看tansforms.py说明文档&#xff1a; ToTensor类作用是&#xff1a;将一个PIL图片或numpy形式转换成tensor的数据类型 python的用法-》tensor数据类型 通过 transforms.ToTensor去看两个问题 1、transforms该如何使用(python) 2、为什么我们需要Te…

4.4【共享源】克隆实战开发之截屏(二)

三,显示器截图 screen_read_display() 函数则用于捕获显示器的屏幕截图。我们需要在特权上下文中工作,以便可以完全访问系统的显示属性。我们可以通过调用具有 SCREEN_DISPLAY_MANAGER_CONTEXT 上下文类型的 screen_create_context() 来创建特权上下文。进程必须具有 root 的…

锯齿云服务器租赁使用教程

首先登陆锯齿云账号 网盘上传数据集与代码 随后我们需要做的是将所需要的数据集与代码上传到网盘&#xff08;也可以直接在租用服务器后将数据集与代码传到服务器的硬盘上&#xff0c;但这样做会消耗大量时间&#xff0c;造成资源浪费&#xff09; 点击工作空间&#xff1a;…

ApsaraMQ Serverless 演进之路,助力企业降本

作者&#xff1a;家泽 ApsaraMQ 与时俱进&#xff0c;砥砺前行 阿里云消息队列从诞生开始&#xff0c;至今已有十余年。今年&#xff0c;阿里云消息产品全面品牌升级为 ApsaraMQ&#xff0c;与时俱进&#xff0c;砥砺前行。 2012 年&#xff0c;RocketMQ 诞生于集团内部&…

Spring Boot实践指南

一.SpringBoot入门案例 SpringBoot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化Spring应用的初始搭建以及开发过程 原生开发SpringMVC程序过程 在没有SpringBoot前&#xff1a; 1.入门案例开发步骤 &#xff08;1&#xff09;创建新模块&#xff0c;选…

PostGreSQL:货币类型

货币类型&#xff1a;money money类型存储固定小数精度的货币数字&#xff0c;小数的精度由数据库的lc_monetary设置决定。windows系统下&#xff0c;该配置项位于/data/postgresql.conf文件中&#xff0c;默认配置如下&#xff0c; lc_monetary Chinese (Simplified)_Chi…

【Filament】纹理贴图

1 前言 本文主要介绍使用 Filament 实现纹理贴图&#xff0c;读者如果对 Filament 不太熟悉&#xff0c;请回顾以下内容。 Filament环境搭建绘制三角形绘制矩形绘制圆形绘制立方体 Filament 纹理坐标的 x、y 轴正方向分别朝右和朝上&#xff0c;其 y 轴正方向朝向与 OpenGL ES…

免费PHP完美运营的最新短视频打赏系统学习版

免费PHP完美运营的最新短视频打赏系统学习版 一、介绍 免费PHP完美运营的最新短视频打赏系统学习版&#xff0c;是一款基于PHP开发的打赏系统&#xff0c;具有强大的功能和稳定的性能。相比于市面上的其他打赏系统&#xff0c;它更加完善&#xff0c;几乎无bug&#xff0c;能…

PMP项目管理 - 进度管理

系列文章目录 系统架构设计 PMP项目管理 - 整合管理 PMP项目管理 - 范围管理 PMP项目管理 - 质量管理 PMP项目管理 - 采购管理 PMP项目管理 - 资源管理 PMP项目管理 - 风险管理 PMP项目管理 - 沟通管理 现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞…

Could not resolve com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.28.

1、首先进入阿里云maven仓库&#xff0c;在搜索栏输入无法下载的依赖名称&#xff0c;查询现有版本号&#xff0c;可以看到这里有2.9.34。 2、在build.gradle(Project)的buildscript闭包下替换为阿里云maven仓库&#xff1a; maven { url https://www.jitpack.io } maven { u…

CentOs 安装MySQL

1、拉取安装包 wget --no-check-certificate dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm 成功拉取 2、安装 yum install mysql-community-release-el6-5.noarch.rpm 过程中可能需要你同意一些东西&#xff0c;y 即可 然后稍微检查一下 yum repolist enabled…

Java实现非对称加密【详解】

Java实现非对称加密 1. 简介2. 非对称加密算法--DH&#xff08;密钥交换&#xff09;3. 非对称加密算法--RSA非对称加密算法--EIGamal5. 总结6 案例6.1 案例16.2 案例2 1. 简介 公开密钥密码学&#xff08;英语&#xff1a;Public-key cryptography&#xff09;也称非对称式密…

Spring中的上下文工具你写的可能有bug

文章目录 前言功能第一种&#xff1a;ApplicationContext第二种方式&#xff1a;ApplicationContextAware第三种&#xff1a;BeanFactoryPostProcessor 源码第一种第二种第三种 前言 本篇是针对如何写一个比较好的spring工具的一个探讨。 功能 下面三种方式&#xff0c;你觉…

第1课 配置FFmpeg+OpenCV开发环境

一、配置开发环境 1.下载FFmpegOpenCV开发所用的SDK压缩包&#xff0c;并解压到E:\SDK下&#xff0c;解压后的路径应为&#xff1a;E:\SDK\ffmpeg-sdk\58\x86\dll及E:\SDK\opencv-sdk\340\x86\dll。 2.新建VC项目&#xff0c;名称为demo1&#xff0c;项目类弄为MFC应用程序&a…

Django 中集成 CKEditor 富文本编辑器详解

概要 在 Web 应用中&#xff0c;富文本编辑器是提高用户体验的重要组件之一。CKEditor 是一款流行的、功能丰富的富文本编辑器。在 Django 项目中集成 CKEditor 不仅可以提升内容编辑的灵活性&#xff0c;还能丰富用户的互动体验。本文将详细介绍如何在 Django 中集成和配置 C…

掌握函数式组件:迈向现代化前端开发的关键步骤(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

【pynput】鼠标行为追踪并模拟

文章目录 前言基本思路安装依赖包实时鼠标捕获捕获鼠标位置捕获鼠标事件记录点击内容 效果图 利用本文内容从事的任何犯法行为和开发与本人无关&#xff0c;请理性利用技术服务大家&#xff0c;创建美好和谐的社会&#xff0c;让人们生活从繁琐中变得更加具有创造性&#xff01…

【SassVue】仿网易云播放器动画

简介 仿网易云播放动画 效果图&#xff08;效果图&#xff09; 最终成品效果 动画组件 src/components/musicPlay.vue <template><div class"music-play"><div></div><div></div><div></div></div> </te…