目录
栈的定义
栈的结构选取
链式储存结构和顺序栈储存结构的差异
栈的代码实现
"stack.h"
"stack.c"
总结
栈的定义
栈:栈是限定仅在表尾进行插入和删除操作的线性表。
我们把运行插入的和删除的一段叫做栈顶(TOP),另一段叫做栈底(BOTTOM),不含任何数据元素的栈称为空栈。栈由称后进先出(Last In Fast Out)的线性表,简称LIFO结构。
栈的插入操作,叫做进栈,也称压栈,入栈。
栈的删除操作,叫做出栈,也叫做弹栈。
首先,我们来举几个比较容易理解的生活中的例子来帮助我们理解栈的特性吧。
首先,我们可以看到上面的烤串,是不是很有食欲,想想一下,当我们串肉到烤串上的时候,是不是一串一串的把肉穿上去,并将它移到稍微下面一点的位置,我们暂且叫它栈底吧,然后我们会继续的将一块一块的肉串上去,直到串到木签的最上方,我们就称它为栈定吧。这种就是入栈的方式。
然后,当烤串烤好了的时候,端上桌子的时候,你拿起一串,是不是从最上方开始吃,最后再吃最下方的,这就是出栈的方式。
我们再来看一看枪类武器的弹夹。当我们上子弹的时候,最先上进弹夹的子弹在最下面,最后上进去的子弹在最上面,当我们开枪打出的时候,最上面的子弹先被打出,最下面的子弹会被最后打出,其实这也和我们的栈有一点联系。
我们再来看看,是不是每一个网页的左上角都有一个后退的标识呢,这就和我们的栈有关。
栈的结构选取
当我们来实现栈的时候,可以使用链式储存结构和顺序栈的储存结构来实现。
链式储存结构和顺序栈储存结构的差异
首先,我们一般不会使用链式储存结构来实现栈,首先我们要明确栈的特性,它只需要从一端入一端出。对比一下顺序栈和链栈,它们入数据出数据的时候再空间复杂度上都是相同的,都是O(1)。对于空间性能来说,顺序栈的空间是固定的,如果空间不够就需要扩容,这样就会导致空间浪费,但它的优点就是定位很方便。但是对于链栈来说,我们需要要求每一个节点都需要有一个指针域,这同时也增加了一些内存的开销,但对于栈的长度无限制。
如果栈的使用过程中元素变化不可料,有时很小,有时很大,那么最好是使用链栈,反之,如果它的变化在可控范围内,建议使用顺序栈会好一些。
栈的代码实现
"stack.h"
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
//函数声明 结构体实现
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include "stack.h"
typedef int stdatatype;
typedef struct stack
{
stdatatype* arr;
int top;
int capcity;
}stack;
//初始化栈
void Initstack(stack* st);
//销毁栈
void DestroyStack(stack* st);
//压栈
void Pushstack(stack* st, stdatatype x);
//出栈
void Popstack(stack* st);
//返回栈顶元素
stdatatype Topstack(stack* st);
//栈元素大小
int StackSize(stack* st);
//判断栈是否为空
bool StackEmpty(stack* st);
"stack.c"
#include "stack.h"
//函数实现
//初始化栈
void Initstack(stack* st)
{
assert(st);
//默认给4个元素的空间大小
st->arr = (stdatatype*)malloc(sizeof(stdatatype) * 4);
if (st->arr == NULL)
{
perror("malloc fail");
//-1表示异常退出
exit(-1);
}
st->capcity = 4;
//栈顶为有效元素的下一位
st->top = 0;
}
//销毁栈
void DestroyStack(stack* st)
{
assert(st);
//直接释放掉
free(st->arr);
//将指针置空
st->arr = NULL;
st->capcity = 0;
st->top = 0;
}
//压栈
void Pushstack(stack* st, stdatatype x)
{
assert(st);
//需要判断空间是否够用,不够就扩容
if (st->capcity == st->top)
{
stdatatype*tmp= (stdatatype*)realloc(st->arr, sizeof(stdatatype) * 2 * st->capcity);
if (tmp == NULL)
{
perror("realloc fail");
//-1表示异常退出
exit(-1);
}
st->arr = tmp;
st->capcity *= 2;
}
//直接栈顶插入,然后top++
st->arr[st->top] = x;
st->top++;
}
//出栈
void Popstack(stack* st)
{
assert(st);
assert(st->top > 0);
//直接top--
st->top--;
}
//返回栈顶元素
stdatatype Topstack(stack* st)
{
assert(st);
assert(st->top > 0);
return st->arr[st->top-1];
}
//栈元素大小
int StackSize(stack* st)
{
assert(st);
return st->top;
}
//判断栈是否为空
bool StackEmpty(stack* st)
{
assert(st);
//为空top=0 f
return st->top == 0;
}
总结
栈是一种比较特殊的结构,它的特性就是先入后出,后入先出,它的主要应用是在递归中。最后送同学们一些话。
人生,就像是一个很大的栈演变。出生时你赤条条地来到人世,慢慢地长大,渐渐地变老,最终还得赤条条地离开人世间。
人生,更需要有进栈出栈的精神体现。在哪里跌倒,就应该在哪里爬起来。无论陷入何等的困境,只要抬头能仰望蓝天,就有希望,不断进取,你就可以让出头之日重现。困难不会永远存在,强者才能勇往直前。
希望我上面分享的对于栈的理解对大家有所帮助。