客厅才看的栈详解

目录

    1.栈的概念和结构

    2.栈的实现

        (1)栈的初始化

        (2)栈的销毁

        (3)入栈

        (4)出栈

        (5)取栈顶元素

        (6)获取栈中有效元素个数

        (7)栈是否为空

 1.栈的概念和结构

栈是一种特殊的线性表,其只允许在固定的一端进行删除和插入操作,进行插入和删除的一端称为栈顶,另一端成为栈底。栈的特殊就在于它是一种先进后出的结构

压栈:栈插入数据的操作叫做压栈/进栈/入栈,入数据在栈顶。

出栈:栈的删除数据操作叫做出栈,出数据也在栈顶。

如图

咱们来思考栈的底层用的是链表还是数组?栈是需要频繁的进行插入数据和删除数据的,而如果使用链表作为栈的底层逻辑的话,我们需要每次都遍历到含有NULL的结点,这样的时间复杂度会比较高,而我们要是使用数组来实现栈的话,只需要在后面直接插入数据即可。

2.栈的实现

(1)栈的初始化

typedef int Stackdatatype;
typedef struct Stack
{
   Stackdatatype * arr;
   int top;
   int capacity;
}Stack;

栈可以存储任何类型的数据,所以我们使用关键字typedef重命名,选择top来表示栈顶的元素,capcity来表示栈的容量。

接下来,我们来试着给栈初始化

typedef int Stackdatatype;
typedef struct Stack
{
   Stackdatatype * arr;
   int top;
   int capacity;
}Stack;

void Stackinit(Stack * ps)//使用ps指针变量来接收st的地址
{
   ps->arr = NULL;
   ps->top = ps->capacity = 0;
}

int main()
{
   Stack st;//先定义结构体变量st
   Stackinit(&st);//把结构体变量st的地址传过去
}

(2)栈的销毁

栈的销毁可以说与栈的初始化如出一辙,把指向栈的指针arr置为NULL,并把top以及capacity置为0即可。

(3)入栈

入栈是从栈顶放进数据的,先放的数据落入栈顶,但是我们需要对栈进行扩容,也就是增加capacity。

typedef int Stackdatatype;
typedef struct Stack
{
   Stackdatatype * arr;
   int top;
   int capacity;
}Stack;

void Stackinit(Stack * ps)//使用ps指针变量来接收st的地址
{
   ps->arr = NULL;
   ps->top = ps->capacity = 0;
}

void Stackcheck(Stack * ps)
{
   int newcapacity = ps->capacity == 0? 4 : 2*capacity;//为0,newcapacity就为4,不为0就是capacity的两倍,相当于扩容两倍
   Stack * tmp = (Stack *)realloc(ps->arr,sizeof(Stackdatatype)*newcapacity);
   if(tmp == NULL)
  {
     return NULL;//如果扩容失败,就返回空指针NULL
  }
   //走到这里,说明扩容成功
   ps->arr = tmp;//把扩容成功后指向该空间的指针重新赋值给arr
   capacity = newcapacity;

}

int main()
{
   Stack st;//先定义结构体变量st
   Stackinit(&st);//把结构体变量st的地址传过去
   Stackcheck(&st);
}

现在,我们有四个int型内存的空间了,如图

那么,我们现在入栈就是从栈顶放入数据,最终会落入栈底,假设我们现在入栈一个4

void Stackcheck(Stack * ps)
{
   int newcapacity = ps->capacity == 0? 4 : 2*capacity;//为0,newcapacity就为4,不为0就是capacity的两倍,相当于扩容两倍
   Stack * tmp = (Stack *)realloc(ps->arr,sizeof(Stackdatatype)*newcapacity);
   if(tmp == NULL)
  {
     return NULL;//如果扩容失败,就返回空指针NULL
  }
   //走到这里,说明扩容成功
   ps->arr = tmp;//把扩容成功后指向该空间的指针重新赋值给arr
   capacity = newcapacity;


void Stackpush(Stack * ps,x)//用x来接收4
{
   if(ps->top == ps->capacity)//top跟capacity相等就说明栈的空间满了,需要扩容
   {
      Stackcheak(ps);
   }
   ps->arr[ps->top] = x;
   ps->top++;
}

int main()
{ 
   Stack st;
   Stackpush(&st,4);//在st这个栈中,入一个4
   return 0;
}

入栈成功,如下图

现在我们想要再入几个数据,例如我们想要入3 ,2 ,1

即下图

(4)出栈

入上图,出栈就很直观了。我们先入的4,只能放在最底下等着最后一个出栈;我们最后入的栈1,就可以最先出栈。也就印证了栈的特点——先入后出

现在,我们来实现出栈的操作,其实出栈很简单,直接top--,把1给覆盖了,如图

但是,我们需要注意一个前提,就是栈为空的时候(栈中不存放任何数据),是不能出栈的。你栈中都没数据,你出栈干嘛呢?你说是吧

所以我们要提前判断栈是否为空。上代码

bool Stackempty(Stack * ps)
{
   assert(ps);//ps不能为空,不然这个判断就无意义了
   return ps->top == 0;//如果top为0,就返回true,反之,返回false
}
void Stackpop(Stack * ps)//出栈的函数
{
   assert(!Stackempty(ps));//栈不为空,才能进行出栈操作
   ps->top--;//top往下走一步,覆盖掉最前面的数据
}

(5)取栈顶元素

请注意,这里是取栈顶元素,并不是删除栈顶的元素,只是返回栈顶的元素,并不影响原先的栈结构

假设我们入栈4 3 2 1,那么栈顶就是1,我们就把1返回

代码显示如下

Stackdatatype StackTop(Stack * ps)
{
   return ps->arr[ps->top - 1];
}

  (6)获取栈中有效元素个数

这个就很简单了,只需要把栈中的元素个数返回就好了,假设我们栈中存储了5个数据,那就返回数字5

代码示例:

int Stacksize(Stack * ps)
{
   return ps->top;//top的大小刚好就为栈中的的元素个数
}

 (7)栈是否为空

前面已经讲过了,其实就调用布尔类型的函数即可

本篇博客就介绍到这里,有疑问的可以私信博主,博主免费为大家解答

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值