数据结构————栈的讲解(超详细!!!)

1 栈的概念和结构

1.1 栈的概念

栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作,进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵循后进先出(先进后出)原则。特性与栈的结构有关

1.2 栈的结构

上述图就是栈的图,小编说过栈是有栈顶和栈底,栈顶可进行插入和删除操作,另一端是封闭的,不进行任何操作。

2 栈的实现(基于顺序表实现)

在讲解栈之前,由于栈是一种线性表,可以使用顺序表实现,也可以使用链表实现,考虑到成本,顺序表表的实现成本低,在尾部增加数据上操作更简便。

typedef int STDataType;

typedef struct stack {

STDataType* arr; //数组,类型可能不是一定的所以用typedef替换一下

int capacity; //总空间大小

int top; //栈顶表示

}ST;

2.1 栈的初始化

任何一个数据结构对其进行初始化是个必备操作,将数组值为空,同时将空间大小和元素个数都置为0,代码如下:

void STInit(ST* ps)

{

assert(ps);

ps->arr = NULL;

ps->capacity = ps->top = 0; //总空间个数和有用空间个数都初始化为0

}

2.2 栈的销毁

有了初始化操作,自然而然就有着销毁操作,毕竟"有始有终" ,栈的销毁同样也是不难的,我们对于arr,需要判断它是否开辟了空间,如果开辟了就free掉,没有开辟就直接把栈的空间大小和栈顶都置为空就好,下面直接上代码图:

void STDestroy(ST* ps)

{

if (ps -> arr) //先判断是否进行动态内存开辟了

{

free(ps -> arr);

}

ps->capacity = ps->top = 0;

}

2.3 入栈

在进行完初始化操作以后,就要进行一些正式操作了,看着入栈这个名字很高大尚,以小编的话来说这其实就是栈的尾插(栈也只能尾插,因为只能从栈顶插入),就类似下图:

上面这个图就展示了入栈操作,其实就是我们在顺序表阶段写的尾插操作,首先我们需要先设置一个函数,来判断一下栈的总空间大小和栈顶是否是相等,如果相等了那就扩容,这个和顺序表的扩容是一样的,详情可以看小编之前写的那一篇,由于栈的插入只有入栈这一种,所以扩容操作直接写到函数内部就好,我们在进行完插入以后,直接往栈顶插入数据,然后让栈顶在想后走一步就好了,下面直接展示代码:

void STPush(ST* ps, STDataType x) //类似顺序表的尾插

{

if (ps->capacity == ps->top)

{

int newcaopacity = ps->capacity == 0 ? 4 : 2 * ps -> capacity;

STDataType* arr1 = (STDataType*)realloc(ps->arr, newcaopacity * sizeof(STDataType));

assert(arr1);

ps->arr = arr1;

ps->capacity = newcaopacity;

} //扩容完成

ps->arr[ps->top++] = x;

}

2.4 出栈

有入栈肯定就会有出栈,对于栈的出栈,其实就是顺序表的尾删操作,因为栈的元素只能从栈顶出,栈底是不可以出元素的,可以类比下图进行记忆:

2.5 栈是否为空

取栈顶元通过上图我们就可以知道出栈到底是什么东西,对于出栈,我们首先需要判断栈是不是空的,不然拿什么来出栈?所以此时我们得写一个布尔类型函数来判断一下此时的栈是否是空的,如果是空的返回true,不是真的返回false,此时我们进需要判断栈顶是否为0就好,下面小编直接给代码图:

bool panduan(ST * ps)

{

assert(ps);

return ps -> top == 0; //这个是来判断栈是不是空了

}

2.6 取栈顶元素

对于上面的代码,小编其实写的很简略,其实如果写麻烦一点我们需要使用选择语句来判断一下是否为空,这里小编直接使用一句话来跳过选择语句了,这个代码的含义就是如果右边是对的那么直接返回true,如果栈顶不为0直接返回false。当我们判断完以后,可以直接进行尾删操作,很简单,我们只需呀让栈顶减一就好了,此时我们就实现了出栈操作,下面给出代码图:

void STPop(ST* ps)

{

assert(ps);

assert(!panduan(ps));

ps->top--;

}

2.7 获取栈中有效元素个数

int STSize(ST* ps)

{

return ps->top;

}

3 代码展示

3.1 Stack.c

#include"Stack.h"

void STInit(ST* ps)

{

ps->arr = NULL;

ps->capacity = ps->top = 0; //总空间个数和有用空间个数都初始化为0

}

void STDestroy(ST* ps)

{

if (ps -> arr) //先判断是否进行动态内存开辟了

{

free(ps -> arr);

}

ps->capacity = ps->top = 0;

}

void STPush(ST* ps, STDataType x) //类似顺序表的尾插

{

if (ps->capacity == ps->top)

{

int newcaopacity = ps->capacity == 0 ? 4 : 2 * ps -> capacity;

STDataType* arr1 = (STDataType*)realloc(ps->arr, newcaopacity * sizeof(STDataType));

assert(arr1);

ps->arr = arr1;

ps->capacity = newcaopacity;

} //扩容完成

ps->arr[ps->top++] = x;

}

bool panduan(ST * ps)

{

assert(ps);

return ps -> top == 0; //这个是来判断栈是不是空了

}

void STPop(ST* ps)

{

assert(ps);

assert(!panduan(ps));

ps->top--;

}

STDataType STTop(ST* ps)

{

return ps->arr[ps->top - 1];

}

int STSize(ST* ps)

{

return ps->top;

}

3.2 Stack.h

#include<stdio.h>

#include<stdlib.h>

#include<assert.h>

#include<stdbool.h> //存放布尔类型的头文件

//下面来复习一下栈的创建

//它的底层代码是数组(也可以理解为顺序表)

typedef int STDataType;

typedef struct stack {

STDataType* arr; //数组,类型可能不是一定的所以用typedef替换一下

int capacity; //总空间大小

int top; //栈顶表示

}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);

相关推荐
Hera_Yc.H5 小时前
数据结构之一:复杂度
数据结构
肥猪猪爸7 小时前
使用卡尔曼滤波器估计pybullet中的机器人位置
数据结构·人工智能·python·算法·机器人·卡尔曼滤波·pybullet
linux_carlos7 小时前
环形缓冲区
数据结构
readmancynn7 小时前
二分基本实现
数据结构·算法
Bucai_不才7 小时前
【数据结构】树——链式存储二叉树的基础
数据结构·二叉树
盼海7 小时前
排序算法(四)--快速排序
数据结构·算法·排序算法
一直学习永不止步7 小时前
LeetCode题练习与总结:最长回文串--409
java·数据结构·算法·leetcode·字符串·贪心·哈希表
珹洺8 小时前
C语言数据结构——详细讲解 双链表
c语言·开发语言·网络·数据结构·c++·算法·leetcode
几窗花鸢8 小时前
力扣面试经典 150(下)
数据结构·c++·算法·leetcode
.Cnn9 小时前
用邻接矩阵实现图的深度优先遍历
c语言·数据结构·算法·深度优先·图论