当前位置: 首页 > news >正文

【数据结构】栈


🍃 如果觉得本系列文章内容还不错,欢迎订阅🚩
🎊个人主页:小编的个人主页
🎀 🎉欢迎大家点赞👍收藏⭐文章
✌️ 🤞 🤟 🤘 🤙 👈 👉 👆 🖕 👇 ☝️ 👍

目录

  • 🐼前言
  • 🐼栈
  • 🐼初始化栈
  • 🐼入栈
  • 🐼判空
  • 🐼出栈
  • 🐼取栈顶元素
  • 🐼栈的有效元素个数
  • 🐼销毁栈
  • 🐼全部源码
  • 🐼文末

🐼前言

🌟在上一节我们实现了双链表,如果感兴趣的小伙伴,可以阅读我的上一篇文章:> 双链表,这一节小编给大家介绍一种特殊的线性表:

🐼栈

✨栈是一种特殊的线性表,它只允许在一端进行操作,进行操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
在这里插入图片描述
我们之前学习了链表和数组存储数据结构,那么栈底层是什么存储的呢?
其实用链表和数组都可以实现栈。刚刚说了,栈都是在栈顶进行插入和删除数据,那么如果是链表,每次都要找尾,时间复杂度为O(N),不过如果颠倒,把栈顶放在链表的头部,那么操作和删除元素即头插和头删时间复杂度都为O(1),不过为了方便,而且数组在尾上插入数据的代价比较小,在栈顶(数组尾部)插入和删除数据,时间复杂度都为O(1),因此数组的实现更优一点,我们这里选择数组来作为栈的底层结构

🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟

✨既然是用数组来存储,我们希望是动态数组,即可增容,这不就和顺序表的结构定义一样吗?
动态顺序栈定义如下:

typedef int STDataType;
//定义顺序栈的结构
typedef struct Stack
{STDataType* arr;int top;//栈顶指针int capacity;//容量
}ST;

下面我们实现栈14`532

🐼初始化栈

void StackInit(ST* ps)
{assert(ps);ps->arr = (STDataType*)malloc(sizeof(STDataType) * 4);if (ps->arr == NULL){perror("malloc fail");exit(-1);}ps->capacity = 4;ps->top = 0;
}

🌻代码解析

💫初始我们先给栈结构成员变量数组指针申请了四个整形空间的大小。将容量初始设为4,栈顶指针置为0。
(注意:top也可以置为-1,置为-1即top即是元素下标;如果top = 0即top指向当前元素的下一个位置,也就是有效的数据个数,所以不一定只有这种写法)
💫时间复杂度为O(1),程序执行常数次,空间复杂度为O(1),只创建有效个变量

🐼入栈

//入栈
void StackPush(ST* ps, STDataType x)
{assert(ps);//判断是否需要增容if (ps->capacity == ps->top){STDataType* tmp =(STDataType*)realloc(ps->arr, ps->capacity*sizeof(STDataType) * 2);if (tmp == NULL){perror("relloc fail");exit(-1);}ps->arr = tmp;ps->capacity *= 2;}ps->arr[ps->top++] = x;
}

🌻代码解析

因为这里是动态栈,所以入栈首先要检查栈容量是否足够,如果不够,对数组进行增容,然后更新capacity,插入元素x,最后更新栈顶指针。
时间复杂度为O(1),程序执行常数次,空间复杂度为O(1),只创建有效个变量
🍂画图剖析:
在这里插入图片描述

🍀测试结果:
在这里插入图片描述

🐼判空

//判空
bool StackEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}

🌻代码解析

通过布尔类型的返回值,如果栈为空,即top = 0;
时间复杂度为O(1),程序执行常数次,空间复杂度为O(1),只创建有效个变量

🐼出栈

//出栈
void StackPop(ST* ps)
{assert(!StackEmpty(ps));ps->top--;
}

🌻代码解析

💫断言保证栈不为空,接着只需要更新top的值,完成出栈操作。(并不是真正把栈顶元素删除了,而是通过栈顶指针的指向,这样操作不会影响到其他函数,跟真正删除效果是一样的)
💫时间复杂度为O(1),程序执行常数次,空间复杂度为O(1),只创建有效个变量
🍂画图剖析:
在这里插入图片描述

🐼取栈顶元素

//取栈顶元素
STDataType StackTop(ST* ps)
{assert(!StackEmpty(ps));return ps->arr[ps->top - 1];
}

🌻代码解析

断言保证栈不为空,直接返回栈顶元素,由于top指向栈顶的下一个位置,所以top要-1

💫时间复杂度为O(1),程序执行常数次,空间复杂度为O(1),只创建有效个变量
🍂画图剖析:
在这里插入图片描述
🍀测试结果:
在这里插入图片描述

🐼栈的有效元素个数

//栈的有效元素个数
int STsize(ST* ps)
{assert(!StackEmpty(ps));return ps->top;
}

🌻代码解析

断言保证栈不为空,直接返回有效元素top。
时间复杂度为O(1),程序执行常数次,空间复杂度为O(1),只创建有效个变量

🐼销毁栈

//销毁栈
void STDestory(ST* ps)
{assert(ps );if(ps->arr)free(ps->arr);ps->capacity = ps->top = 0;ps->arr = NULL;
}

🌻代码解析

如果指向数组的那块连续空间存在,直接销毁,并将capacity和top的值置为初始值,并将指向数组的指针置为空,防止野指针解引用。
💫时间复杂度为O(1),程序执行常数次,空间复杂度为O(1),只创建有效个变量

🍀测试结果:
在这里插入图片描述

🍀栈整体测试:
在这里插入图片描述

🐼全部源码

Stack.h

#define  _CRT_SECURE_NO_WARNINGS#include<stdio.h>
#include<assert.h>
#include <stdlib.h>
#include <stdbool.h>typedef int STDataType;
//定义顺序栈的结构
typedef struct Stack
{STDataType* arr;int top;//栈顶指针int capacity;//容量
}ST;//初始化栈
void StackInit(ST* ps);
//销毁栈
void STDestory(ST* ps);
//入栈
void StackPush(ST* ps, STDataType x);
//出栈
void StackPop(ST* ps);
//取栈顶元素
STDataType StackTop(ST* ps);
//判空
bool StackEmpty(ST* ps);
//栈的有效元素个数
int STsize(ST* ps);

Stack.c

#include "Stack.h"
//初始化栈
void StackInit(ST* ps)
{assert(ps);ps->arr = (STDataType*)malloc(sizeof(STDataType) * 4);if (ps->arr == NULL)//第一次发现少了个等号{perror("malloc fail");exit(-1);}ps->capacity = 4;ps->top = 0;
}//销毁栈
void STDestory(ST* ps)
{assert(ps );if(ps->arr)free(ps->arr);ps->capacity = ps->top = 0;ps->arr = NULL;
}//入栈
void StackPush(ST* ps, STDataType x)
{assert(ps);//判断是否需要增容if (ps->capacity == ps->top){STDataType* tmp =(STDataType*)realloc(ps->arr, ps->capacity*sizeof(STDataType) * 2);if (tmp == NULL){perror("relloc fail");exit(-1);}ps->arr = tmp;ps->capacity *= 2;}ps->arr[ps->top++] = x;
}
//判空
bool StackEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}//出栈
void StackPop(ST* ps)
{assert(!StackEmpty(ps));ps->top--;
}//取栈顶元素
STDataType StackTop(ST* ps)
{assert(!StackEmpty(ps));return ps->arr[ps->top - 1];
}//栈的有效元素个数
int STsize(ST* ps)
{assert(!StackEmpty(ps));return ps->top;
}

test.c

void test01()
{ST sl;StackInit(&sl);StackPush(&sl, 1);StackPush(&sl, 2);StackPush(&sl, 3);StackPush(&sl, 4);while (!StackEmpty(&sl)){int tmp = StackTop(&sl);printf("%d ", tmp);StackPop(&sl);}printf("\n");STDestory(&sl);}

🐼文末

感谢你看到这里,如果觉得本篇文章对你有帮助,点个赞👍 吧,你的点赞就是我更新的最大动力 ⛅️🌈 ☀️


http://www.mrgr.cn/news/53901.html

相关文章:

  • Windows下部署autMan
  • 鸿蒙 app上怎么实现阴影效果
  • QT开发--QT SQL模块
  • 专家辅助证人出庭质证实务运用之技巧
  • 面对AI算力需求激增,如何守护数据中心机房安全?
  • 【Flutter】Dart:运算符
  • 数仓建设:如何设计数据治理考评规则?
  • 类和对象(中)后面部分
  • 【note】GNN
  • Dropout为何能防止过拟合?dropout和BN 在前向传播和方向传播阶段的区别?
  • 「图::连通」详解并查集并实现对应的功能 / 手撕数据结构(C++)
  • 挑战自闭症儿童康复:探索有效治疗方法
  • C#从零开始学习(类型和引用)(4)
  • 解锁C++多态的魔力:灵活与高效的编码艺术(下)
  • 每日一题——第一百一十七题
  • 【部署篇】rabbitmq-01介绍
  • 【openGauss】OPENGAUSS/POSTGRESQL 中float类型到int类型的隐式转换
  • 直播带货APP开发指南:基于多商户商城系统源码的方案实战
  • vscode 预览markdown 文件
  • 竹壳天气时钟(三)TFT屏幕显示中文
  • 量价关系总结
  • Redis入门到精通(二):入门Redis看这一篇就够了
  • AI动漫翻唱项目玩法拆解,起号涨粉咔咔猛,实操干货分享
  • ICMP协议以及ARP欺骗攻击
  • 跨平台进程池背后的思想
  • 【数据结构与算法】之二分查找