数据结构–栈

数据结构–栈

什么是栈?

  • 首先先给大家讲一下栈是什么:
  • 栈是一种特殊的线性表。特殊之处就在于对栈的操作的特殊。对于栈,只允许其在固定的一端进行插入和删除元素操作。不像普通的顺序表,链表,可以在任意位置进行删除插入元素的操作。
  • 那么“进行数据插入和删除操作的一端”就被称作为栈顶,另一端被称为栈底。栈中的元素遵守着后进先出,或者说先进后出的原则。(因为只允许在一端进行插入删除,假设栈中已经存有元素,那么我要取出第一个存进去的元素,就要先把后面的元素一个个拿出来,才能把第一个存进去的元素取出来)
  • 压栈:栈的插入操作叫做进栈、压栈、入栈(不同的叫法)。插入数据都在栈顶
  • 出栈:栈的删除操作叫做出栈。删除数据,取出数据,也在栈顶。

请添加图片描述

栈的实现

  • 栈的实现有两种实现方式,一种就是和顺序表类似,用数组实现,另一种则是通过单链表来实现栈。

在这里插入图片描述

实现代码

  • 头文件.h
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

typedef int SKDataType;
typedef struct Stack
{
    SKDataType *a;
    int top;//栈顶下标
    int capacity;//容量
}SK;

//初始化栈
void SKInit(SK* ps);
//销毁栈
void SKDestroy(SK* ps);

//插入数据,压栈
void SKPush(SK* ps,SKDataType x);
//删除数据,出栈
void SKPop(SK* ps);
//获取现在栈顶元素的值
SKDataType SKTop(SK* ps);

//栈的大小
int SKSize(SK* ps);
//判断栈是否为空
bool SKEmpty(SK* ps);
  • 函数实现文件.c
#include "stack.h"

//初始化栈
void SKInit(SK* ps)
{
    assert(ps);

    ps->a=NULL;
    ps->capacity=0;
    ps->top=0;
}

//销毁栈
void SKDestroy(SK* ps)
{
    assert(ps);

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

//插入数据,压栈
void SKPush(SK* ps,SKDataType x)
{
    assert(ps);


    if(ps->top==ps->capacity)
    {
        int newCapacity=ps->capacity==0 ? 4 :ps->capacity*2;
        SKDataType * tmp=(SKDataType*) realloc(ps->a,sizeof (SKDataType)*newCapacity);
        if(tmp==NULL)
        {
            perror("realloc failed");
            exit(-1);
        }

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

    ps->a[ps->top]=x;
    ps->top++;
}

//删除数据,出栈
void SKPop(SK* ps)
{
    assert(ps);

    assert(ps->top>0);

    ps->top--;
}

//获取现在栈顶元素的值
SKDataType SKTop(SK* ps)
{
    assert(ps);

    assert(ps->top>0);

    return ps->a[ps->top-1];
}

//栈的大小
int SKSize(SK* ps)
{
    assert(ps);

    return ps->top;
}

//判断栈是否为空
bool SKEmpty(SK* ps)
{
    assert(ps);

    return ps->top==0;
}
  • 测试文件.c(仅供参考)
#include "stack.h"

void TestStack1()
{
    SK st;
    SKInit(&st);
    SKPush(&st, 1);
    SKPush(&st, 2);
    SKPush(&st, 3);
    SKPush(&st, 4);
    SKPush(&st, 5);

    while (!SKEmpty(&st))
    {
        printf("%d ", SKTop(&st));
        SKPop(&st);
    }
    printf("\n");

    SKDestroy(&st);
}

int main()
{
    TestStack1();

    return 0;
}

函数讲解

  1. 栈的结构
//取别名,方便更换数据类型,比如你要存char类型数据的时候,直接把int换成char,就可以全局替换数据了
typedef int SKDataType;
typedef struct Stack
{
    SKDataType *a;
    int top;//标记栈顶的工具
    int capacity;//容量
}SK;

在这里插入图片描述

  1. 初始化栈
//初始化栈
void SKInit(SK* ps)
{
    assert(ps);

    ps->a=NULL;
    ps->capacity=0;
    ps->top=0;
}

在这里插入图片描述

  1. 销毁栈
//销毁栈
void SKDestroy(SK* ps)
{
    assert(ps);

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

  • 销毁栈就没什么好说的了,就是把结构体(工具包)里面的本体(数组/栈)给free掉(将动态开辟的空间返还给系统),指针置空,其他值也置为零。
  1. 压栈
//插入数据,压栈
void SKPush(SK* ps,SKDataType x)
{
    assert(ps);

    if(ps->top==ps->capacity)
    {
        int newCapacity=ps->capacity==0 ? 4 :ps->capacity*2;
        SKDataType *tmp=(SKDataType*)realloc(ps->a,sizeof(SKDataType)*newCapacity);
        if(tmp==NULL)
        {
            perror("realloc failed");
            exit(-1);
        }

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

    ps->a[ps->top]=x;
    ps->top++;
}

在这里插入图片描述

  • 如果这部分的解析还是不清楚的话可以先往下看,看完就明白了。
  1. 出栈
//删除数据,出栈
void SKPop(SK* ps)
{
    assert(ps);

    assert(ps->top>0);

    ps->top--;
}
  • 出栈也很简单,我们不需要对栈内元素做什么,我们直接更改下标就好了。让top–,因为我初始化top=0嘛。所以top就是栈顶元素的下一个元素的下标,也就是栈顶元素下标+1,top–之后,原本的栈顶就变成了新栈顶的下一个元素。后续插入数据也不会影响,会被直接覆盖。
  1. 获取现在栈顶元素的值
//获取现在栈顶元素的值
SKDataType SKTop(SK* ps)
{
    assert(ps);

    assert(ps->top>0);

    return ps->a[ps->top-1];
}
  • 这个也没什么好说的,top就是栈顶元素的下标+1,想要获得栈顶元素,top-1就可以了。
  1. 栈的大小(栈中含有的有效元素个数)
//栈的大小
int SKSize(SK* ps)
{
    assert(ps);

    return ps->top;
}
  • 因为我初始化top=0,每次插入元素,top就+1,所以top的大小也是有效元素的大小。
  1. 判断栈是否为空
//判断栈是否为空
bool SKEmpty(SK* ps)
{
    assert(ps);

    return ps->top==0;
}
  • 因为我初始化top=0,这个就标志了栈是没有元素的。和上面计算栈的大小差不多,每次插入元素top+1,所以就可以直接用top==0来判断了。返回的是bool类型,记得带上stdbool.h头文件。
  1. 测试函数说明
#include "stack.h"

void TestStack1()
{
    SK st;
    SKInit(&st);
    SKPush(&st, 1);
    SKPush(&st, 2);
    SKPush(&st, 3);
    SKPush(&st, 4);
    SKPush(&st, 5);

    while (!SKEmpty(&st))
    {
        printf("%d ", SKTop(&st));
        SKPop(&st);
    }
    printf("\n");

    SKDestroy(&st);
}

int main()
{
    TestStack1();

    return 0;
}

在这里插入图片描述

  • 那么栈的内容就大概讲完了。后面会给大家讲道题,帮助大家感受一下,栈的作用。

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

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

相关文章

通过Docker搭个游戏——疯狂大陆(Pkland)

最近在研究我的服务器&#xff0c;在服务器上搭了很多docker的项目&#xff0c;然后找着找着发现一个能用Docker配置环境的游戏叫Pkland。 项目地址&#xff1a;GitHub - popkarthb/pkland: 疯狂大陆是一款多人在线的战略游戏。 游戏操作简捷,您仅需要使用浏览器就可以在任何时…

03.06 QT

一、使用QSlider设计一个进度条&#xff0c;并让其通过线程自己动起来 程序代码&#xff1a; <1> Widget.h: #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QThread> #include "mythread.h"QT_BEGIN_NAMESPACE namespace Ui {…

【LeetCode 热题 100】3. 无重复字符的最长子串 | python 【中等】

美美超过管解 题目&#xff1a; 3. 无重复字符的最长子串 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc"&#xff0c;所以其长度为 3。 注…

微服务拆分-拆分商品服务

复制hm-service模块pom.xml文件里面的依赖到item-service模块pom.xml文件。 需要准备的依赖 <dependencies><!--common--><dependency><groupId>com.heima</groupId><artifactId>hm-common</artifactId><version>1.0.0</v…

父进程和子进程

思维导图&#xff1a; 1.使用父子进程实现一个图片的拷贝 要求父进程拷贝前一部分 子进程拷贝后一部分 使用diff查看两个文件是否相同 #include <head.h> int main(int argc, const char *argv[]) {int fd1open("/home/ubuntu/3.6/xiaoxin.bmp",O_RDONLY);…

3.2、对称加密算法

目录 对称加密算法总结国产加密算法 - SM系列 对称加密算法总结 首先看一下第一个它的全称叫数据加密标准&#xff0c;英文单词是DES&#xff0c;它是一种分组加密算法&#xff0c;就是比如说&#xff0c;我有10t的数据&#xff0c;我先给你做一下分组&#xff0c;比如说就是64…

let、const和var的区别是什么?

文章目录 一、概述二、var 的特点2.1、作用域2.2、提升&#xff08;Hoisting&#xff09;2.3、全局变量2.4、重复声明‌ 三、let 的特点3.1、作用域3.2、提升&#xff08;Hoisting&#xff09;3.3、不允许重复声明 四、const 的特点4.1、作用域4.2、不可变性4.3、提升&#xff…

数一考研复习之拉格朗日中值定理在求解函数极限中的应用,

最近在复习考研数学,只是简单做题过于乏味,因此便总结了一些笔记,后续若有空,也会将自己的复习笔记分享出来。本篇&#xff0c;我们将重点讲解拉格朗日中值定理在求解函数极限中的应用。同时,作者本人作为python领域创作者&#xff0c;还将在本文分享使用sympy求解高数中函数极…

Devart dbForge Studio for MySQL Enterprise 9.0.338高效数据库管理工具

Devart dbForge Studio for MySQL Enterprise 9.0.338 是一款功能强大的 MySQL 数据库管理工具&#xff0c;专为数据库开发人员和管理员设计。它提供了丰富的功能&#xff0c;帮助用户更高效地管理、开发和维护 MySQL 数据库 Devart dbForge Studio for MySQL Enterprise 9.0.…

Android15使用FFmpeg解码并播放MP4视频完整示例

效果: 1.编译FFmpeg库: 下载FFmpeg-kit的源码并编译生成安装平台库 2.复制生成的FFmpeg库so文件与包含目录到自己的Android下 如果没有prebuiltLibs目录,创建一个,然后复制 包含目录只复制arm64-v8a下

DeepSeek大模型 —— 全维度技术解析

DeepSeek大模型 —— 全维度技术解析 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff01;点我试试&#xff01;&#xff01; 文章目录 DeepSeek大模型 —— 全维度技术解析一、模型架构全景解析1.1…

Spring Boot 与 MyBatis 版本兼容性

初接触Spring Boot&#xff0c;本次使用Spring Boot版本为3.4.3&#xff0c;mybatis的起步依赖版本为3.0.0&#xff0c;在启动时报错&#xff0c;报错代码如下 org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name userMapper…

JavaWeb6、Servlet

6.1Servlet简介 Servlet就是sun公司开发动态web的一门技术 sun公司在这些API中提供一个接口叫做Servlet&#xff0c;如果想开发一个Servlet程序&#xff0c;只需要完成两个小步骤&#xff1a; 编写一个类&#xff0c;实现Servlet接口 把开发好的Java类部署到web服务器中 把…

论文粗读——Isometric 3D Adversarial Examples in the Physical World

论文地址:Isometric 3D Adversarial Examples in the Physical World 动机 现有的3D点云攻击方法远远不够隐蔽,并且在物理世界中性能严重下降。 已有方法及其不足 基于梯度的攻击->仅限于数字世界攻击;KNN攻击和GeoA3攻击->点云重建引入了较大的噪声和错误,导致攻…

AI视频领域的DeepSeek—阿里万相2.1图生视频

让我们一同深入探索万相 2.1 &#xff0c;本文不仅介绍其文生图和文生视频的使用秘籍&#xff0c;还将手把手教你如何利用它实现图生视频。 如下为生成的视频效果&#xff08;我录制的GIF动图&#xff09; 如下为输入的图片 目录 1.阿里巴巴全面开源旗下视频生成模型万相2.1模…

微电网协调控制器ACCU-100 分布式光伏 光储充一本化

安科瑞 华楠 18706163979 应用范围&#xff1a; 分布式光伏、微型风力发电、工商业储能、光储充一体化电站、微电网等领域。 主要功能&#xff1a; 数据采集&#xff1a;支持串口、以太网等多通道实时运行&#xff0c;满足各类风电与光伏逆变器、储能等 设备接入&#xff…

Android MVC、MVP、MVVM三种架构的介绍和使用。

写在前面&#xff1a;现在随便出去面试Android APP相关的工作&#xff0c;面试官基本上都会提问APP架构相关的问题&#xff0c;用Java、kotlin写APP的话&#xff0c;其实就三种架构MVC、MVP、MVVM&#xff0c;MVC和MVP高度相似&#xff0c;区别不大&#xff0c;MVVM则不同&…

懒加载预加载

&#xff08;一&#xff09;、懒加载 1.什么是懒加载&#xff1f; 懒加载也就是延迟加载。当访问一个页面的时候&#xff0c;先把img元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径&#xff08;这样就只需请求一次&#xff0c;俗称占位图&#xff09;&#…

Python 中的析构函数:对象生命周期的终结艺术

在 Python 的面向对象编程中&#xff0c;析构函数是一个重要的概念。它主要用于在对象被销毁之前执行一些清理工作&#xff0c;如释放资源、关闭文件或网络连接等。本文将详细介绍 Python 中的析构函数&#xff0c;包括其定义、语法、调用时机以及实际应用场景。 一、什么是析…

使用QT + 文件IO + 鼠标拖拽事件 + 线程 ,实现大文件的传输

第一题、使用qss&#xff0c;通过线程&#xff0c;使进度条自己动起来 mythread.h #ifndef MYTHREAD_H #define MYTHREAD_H#include <QObject> #include <QThread> #include <QDebug>class mythread : public QThread {Q_OBJECT public:mythread(QObject* …