探寻栈的奇妙世界

目录

引言

栈的概念及结构

栈接口实现

结构

初始化 

 入栈

出栈

 取栈顶

判空 

数据个数

释放

总结


引言

欢迎来到我的博客,今天我们将一起探索程序设计中一个不可或缺的数据结构 — 栈。在这篇博客中,我将为你揭开栈的神秘面纱,从栈的基本概念开始,一起探讨其背后的原理。我们将不仅限于理论,更将通过实际接口的实现,让你亲身感受栈的各种操作具体实现方式,最终轻松手撕一个栈。让我们一起踏上栈的探索之旅吧!

栈的概念及结构

栈(Stack)是一种特殊的线性表,它基于后进先出(Last In, First Out,LIFO)的原则。栈可以看作是一系列元素的集合,其中元素的插入和删除操作仅在栈的一端进行,通常称为栈顶,另一端则称为栈底。栈提供了两个主要的操作:
入栈(Push): 将元素添加到栈的顶部,即
插入操作
出栈(Pop): 从栈的顶部移除元素,即
删除操作

如图所示,最后入栈的元素在栈的顶端,所以在栈中,最后一个入栈的元素是第一个出栈的。

栈可以用数组或链表来实现。使用数组来实现的话,我们需要让数组的尾部为栈顶,这样只需要涉及到数组的尾插尾删,我们知道数组的尾插尾删效率是很高的。而如果选择链表实现的话,就需要让链表的头部作为栈顶,因为单向链表的尾插尾删涉及到找尾,效率不高。当然,可以选择使用双向循环链表或者在使用单向链表的基础上同时维护一个头指针和一个尾指针,这样的话首尾任选一端做栈顶即可。本篇博客,我们以数组栈来讲解栈涉及到的操作,当然,实现的是动态栈。


数组实现如上


链表实现如上

栈接口实现

结构

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>typedef int STDataType;typedef struct Stack
{STDataType* data;int Top;       // 栈顶int capacity;  // 容量
}Stack;

可以看到这个结构与顺序表的很类似,只是栈这里用的是Top,事实上和顺序表那里的size的作用是类似的,这里的Top也是表示当前最后一个数据的下一个位置的下标,当栈为空时,Top的值为0

初始化 

void StackInit(Stack* ps)
{assert(ps);ps->capacity = 0;ps->data = NULL;ps->Top = 0;
}

初始化的时候给不给空间都行。我这里的Top是用来指向最后一个数据的下一个位置,如果想让Top就是最后一个数据的下标位置的话,初始化的时候就要让Top为-1。不同的Top在接下来的插入、取栈顶元素和判空等操作在代码上都会有一些细微的差异。 


 

 入栈

void StackPush(Stack* ps, STDataType val)
{assert(ps);  // 断言栈结构非空// 检查是否需要扩容if (ps->capacity == ps->Top){// 计算新容量int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;// 重新分配内存空间STDataType* tmp = (STDataType*)realloc(ps->data, sizeof(STDataType) * newcapacity);if (tmp == NULL){perror("realloc fail");  // 输出错误信息exit(-1);  // 退出程序,表示内存分配失败}// 更新栈的容量和数据存储区域ps->capacity = newcapacity;ps->data = tmp;}// 将元素添加到栈顶,并更新栈顶位置ps->data[ps->Top] = val;ps->Top++;
}

首先,通过断言确保栈结构非空,然后检查栈是否需要扩容。如果当前栈的容量等于栈顶位置,就进行动态内存扩容,如果容量是0的话,就设置为4,否则将栈的容量翻倍。接着,通过 realloc 函数进行扩容操作,如果内存分配失败,输出错误信息并退出程序。最后,将要入栈的元素添加到栈顶,并更新栈顶位置如果Top设置为-1的话,这里就是先让Top加加,再来添加元素

出栈

void StackPop(Stack* ps)
{assert(ps);          // 断言栈结构非空assert(ps->Top > 0); // 断言栈顶位置大于0,确保栈非空ps->Top--;           // 将栈顶位置减一,实现出栈操作
}

首先,通过断言确保栈结构非空。然后,再次通过断言确保栈顶位置大于0,以确保栈非空,因为不能从空栈中执行出栈操作。最后,将栈顶位置减一实现出栈操作,即从栈中移除元素。 

 取栈顶

STDataType StackTop(Stack* ps)
{assert(ps);                    // 断言栈结构非空assert(ps->Top > 0);           // 断言栈顶位置大于0,确保栈非空return ps->data[ps->Top - 1];  // 返回栈顶元素,不改变栈的状态
}

首先,通过断言确保栈结构非空并且栈顶位置大于0,因为不能在空栈中执行获取栈顶元素的操作。最后,通过 ps->Top - 1 访问栈顶位置上的元素,并将其返回。如果Top初始化的时候设置成-1,这里就不需要减去1。

判空 

bool StackEmpty(Stack* ps)
{assert(ps);              // 断言栈结构非空return ps->Top == 0;     // 返回栈顶位置是否为0,判断栈是否为空
}

同理,Top设置为-1的话,这里栈为空的条件就要变成Top为-1。 

数据个数

int StackSize(Stack* ps)
{assert(ps);         // 断言栈结构非空return ps->Top;     // 返回栈顶位置,即栈的当前大小
}

Top设置为-1的话,返回的Top值需要加一。

释放

void StackDestroy(Stack* ps)
{assert(ps);         // 断言栈结构非空free(ps->data);     // 释放栈的数据存储区域的动态分配内存ps->data = NULL;    // 将数据存储区域指针置为NULL,防止悬空指针问题ps->capacity = 0;   // 将栈的容量设为0,表示没有分配内存ps->Top = 0;        // 将栈顶位置设为0,表示栈中没有元素
}

这里使用 free 函数释放栈的数据存储区域的动态分配内存。接着,将数据存储区域指针置为空,以防止悬空指针(野指针)问题。最后,将栈的容量设为0,表示没有分配内存,同时将栈顶位置设为0,表示栈中没有元素。 

总结

通过这篇博客,我们探讨了栈这一重要的数据结构,了解了栈的概念及结构。从栈的基本概念入手,我们逐步展开,详细介绍了栈接口的实现。在结构方面,我们深入研究了栈的初始化、入栈、出栈、取栈顶、判空、数据个数以及释放等关键操作。通过实际的接口实现,读者能够清晰地了解栈的内部机制,读者可以自己实现一下这些接口来加深对栈的理解,或者在力扣上刷上几道栈相关的题目。

 

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

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

相关文章

摄像头为什么需要积分球进行校准?

摄像头均匀光源校准可以提高图像质量、消除误差因素、实现标准化测量、保证测量结果的可靠性&#xff0c;并提高生产效率。因此&#xff0c;对于需要高精度、高清晰度图像的领域&#xff0c;摄像头均匀光源校准是非常必要的。 一、为什么摄像头需要均匀光源校准&#xff1f; 提…

promethesu告警规则配置,alertmanager通过webhook通知

文章目录 前言一、promethesu告警二、告警配置编写rule文件prometheus配置prometheus产生告警 三、告警通知prometheus 配置 alertmanageralertmanager 配置 webhook通知编写接口接收 webhook 总结 前言 如果没有学习过prometheus的基础和监控的同学&#xff0c;可以先过一遍这…

windows系统和虚拟机上ubuntu系统通过虚拟串口进行通信

本文的目的是实现windows系统和虚拟机上安装的ubuntu通过串口进行通信。为了直观观测串口收发数据的内容&#xff0c;需要在windows系统和ubuntu系统使用串口助手来进行监听。windows系统端用的监听工具是串口助手SSCOM&#xff0c;ubuntu系统端使用的串口助手是CuteCom。 ubu…

OpenCVForUnity的首部姿态识别功能

手势识别功能 插件名称&#xff1a;OpenCVForUnity 效果 关键代码 HandPoseEstimationMediaPipeExample MediaPipeHandPoseEstimator 第二步&#xff1a; 性能问题&#xff0c;功能是不错&#xff0c;可是一个手部识别的demo&#xff0c;cpu直接飙满了&#xff0c;这哪行。…

vue2-省市县三级联动选择框

Json数据&#xff1a;https://yjy-oss-files.oss-cn-zhangjiakou.aliyuncs.com/tuxian/area.json 如何访问本地文件参考&#xff1a;vue-访问本地json文件_vue3读取json文件-CSDN博客 .vue文件&#xff1a; <template><select v-model"mailAddress1" style…

TCP一对一通信

package 二十一章; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner;/*** Socket服务端**/ public class SocketServer {public static void main(String[] args) {ServerSocket ss null;Socket s null;try {// 创建监听…

光伏电站全貌

光伏电站 简介 每一篇文章开篇我都会写一个内容简介&#xff0c;一来梳理自己的写作思路&#xff0c;二来方便读者整体了解文章写作意图和脉络。本篇是新能源方面的开篇之作&#xff0c;我选取了介绍光伏电站基础知识&#xff0c;首先我们要了解光伏电站基础分类&#xff0c;然…

导弹制导和打卡系统中GPS经纬度数据库字段类型的选用思路

引言&#xff1a; 在现代科技中&#xff0c;全球定位系统&#xff08;GPS&#xff09;的应用已经渗透到许多领域&#xff0c;包括导弹制导和企业打卡系统。在这两个应用中&#xff0c;GPS经纬度数据的精准性直接影响系统的性能和可靠性。因此&#xff0c;在设计数据库时&#x…

C++STL的string(超详解)

文章目录 前言C语言的字符串 stringstring类的常用接口string类的常见构造string (const string& str);string (const string& str, size_t pos, size_t len npos); capacitysize和lengthreserveresizeresize可以删除数据 modify尾插插入字符插入字符串 inserterasere…

在vscode下将ipynb文件转成markdown(.md文件)的方法

在vscode下将ipynb文件转成markdown&#xff08;.md文件&#xff09;的方法 写在最前面安装nbconvert工具vscode界面 or cmd终端基本命令将ipynb文件转换成md文件 总结 写在最前面 VSCode作为一款强大的代码编辑器&#xff0c;提供了广泛的功能。它支持多种文件格式的编辑和查…

【精选】设计模式——工厂设计模式

工厂设计模式是一种创建型设计模式&#xff0c;其主要目的是通过将对象的创建过程封装在一个工厂类中来实现对象的创建。这样可以降低客户端与具体产品类之间的耦合度&#xff0c;也便于代码的扩展和维护。 工厂设计模式&#xff1a; 以下是Java中两个常见的工厂设计模式示例…

【数据结构 — 排序 — 插入排序】

数据结构 — 排序 — 插入排序 一.排序1.1.排序的概念及其运用1.1.1排序的概念1.1.2排序运用1.1.3 常见的排序算法 二.插入排序2.1.直接插入排序2.1.1.算法讲解2.1.2.代码实现2.1.2.1.函数定义2.1.2.2.算法接口实现2.1.2.3.测试代码实现2.1.2.4.测试展示 2.2.希尔排序2.2.1.算法…