目录

数据结构栈

数据结构–栈

数据结构–栈

什么是栈?

  • 首先先给大家讲一下栈是什么:
  • 栈是一种特殊的线性表。特殊之处就在于对栈的操作的特殊。对于栈,只允许其在固定的一端进行插入和删除元素操作。不像普通的顺序表,链表,可以在任意位置进行删除插入元素的操作。
  • 那么“进行数据插入和删除操作的一端”就被称作为栈顶,另一端被称为栈底。栈中的元素遵守着后进先出,或者说先进后出的原则。(因为只允许在一端进行插入删除,假设栈中已经存有元素,那么我要取出第一个存进去的元素,就要先把后面的元素一个个拿出来,才能把第一个存进去的元素取出来)
  • 压栈:栈的插入操作叫做进栈、压栈、入栈(不同的叫法)。插入数据都在栈顶
  • 出栈:栈的删除操作叫做出栈。删除数据,取出数据,也在栈顶。

https://i-blog.csdnimg.cn/direct/8ac6decaae204e86ac0f28df96242522.png

栈的实现

  • 栈的实现有两种实现方式,一种就是和顺序表类似,用数组实现,另一种则是通过单链表来实现栈。

https://i-blog.csdnimg.cn/direct/af9d3cd2d4ea46518523442895573e9b.png

实现代码

  • 头文件.h
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

typedef int SKDataType;
typedef struct Stack
{
    SKDataType *a;
    int top;//栈顶下标
    int capacity;//容量
}SK;

//初始化栈
void SKInit(SK* ps);
//销毁栈
void SKDestroy(SK* ps);

//插入数据,压栈
void SKPush(SK* ps,SKDataType x);
//删除数据,出栈
void SKPop(SK* ps);
//获取现在栈顶元素的值
SKDataType SKTop(SK* ps);

//栈的大小
int SKSize(SK* ps);
//判断栈是否为空
bool SKEmpty(SK* ps);
  • 函数实现文件.c
#include "stack.h"

//初始化栈
void SKInit(SK* ps)
{
    assert(ps);

    ps->a=NULL;
    ps->capacity=0;
    ps->top=0;
}

//销毁栈
void SKDestroy(SK* ps)
{
    assert(ps);

    free(ps->a);
    ps->a=NULL;
    ps->top=ps->capacity=0;
}

//插入数据,压栈
void SKPush(SK* ps,SKDataType x)
{
    assert(ps);


    if(ps->top==ps->capacity)
    {
        int newCapacity=ps->capacity==0 ? 4 :ps->capacity*2;
        SKDataType * tmp=(SKDataType*) realloc(ps->a,sizeof (SKDataType)*newCapacity);
        if(tmp==NULL)
        {
            perror("realloc failed");
            exit(-1);
        }

        ps->a=tmp;
        ps->capacity=newCapacity;
    }

    ps->a[ps->top]=x;
    ps->top++;
}

//删除数据,出栈
void SKPop(SK* ps)
{
    assert(ps);

    assert(ps->top>0);

    ps->top--;
}

//获取现在栈顶元素的值
SKDataType SKTop(SK* ps)
{
    assert(ps);

    assert(ps->top>0);

    return ps->a[ps->top-1];
}

//栈的大小
int SKSize(SK* ps)
{
    assert(ps);

    return ps->top;
}

//判断栈是否为空
bool SKEmpty(SK* ps)
{
    assert(ps);

    return ps->top==0;
}
  • 测试文件.c(仅供参考)
#include "stack.h"

void TestStack1()
{
    SK st;
    SKInit(&st);
    SKPush(&st, 1);
    SKPush(&st, 2);
    SKPush(&st, 3);
    SKPush(&st, 4);
    SKPush(&st, 5);

    while (!SKEmpty(&st))
    {
        printf("%d ", SKTop(&st));
        SKPop(&st);
    }
    printf("\n");

    SKDestroy(&st);
}

int main()
{
    TestStack1();

    return 0;
}

函数讲解

  1. 栈的结构
//取别名,方便更换数据类型,比如你要存char类型数据的时候,直接把int换成char,就可以全局替换数据了
typedef int SKDataType;
typedef struct Stack
{
    SKDataType *a;
    int top;//标记栈顶的工具
    int capacity;//容量
}SK;

https://i-blog.csdnimg.cn/direct/8b7c733ab14445a7965179620fd9add3.png

  1. 初始化栈
//初始化栈
void SKInit(SK* ps)
{
    assert(ps);

    ps->a=NULL;
    ps->capacity=0;
    ps->top=0;
}

https://i-blog.csdnimg.cn/direct/7f81947b9a554b1ab65a2733108828a4.png

  1. 销毁栈
//销毁栈
void SKDestroy(SK* ps)
{
    assert(ps);

    free(ps->a);
    ps->a=NULL;
    ps->top=ps->capacity=0;
}
  • 销毁栈就没什么好说的了,就是把结构体(工具包)里面的本体(数组/栈)给free掉(将动态开辟的空间返还给系统),指针置空,其他值也置为零。
  1. 压栈
//插入数据,压栈
void SKPush(SK* ps,SKDataType x)
{
    assert(ps);

    if(ps->top==ps->capacity)
    {
        int newCapacity=ps->capacity==0 ? 4 :ps->capacity*2;
        SKDataType *tmp=(SKDataType*)realloc(ps->a,sizeof(SKDataType)*newCapacity);
        if(tmp==NULL)
        {
            perror("realloc failed");
            exit(-1);
        }

        ps->a=tmp;
        ps->capacity=newCapacity;
    }

    ps->a[ps->top]=x;
    ps->top++;
}

https://i-blog.csdnimg.cn/direct/9daa12ccbc3b4474a642415fbe685fc0.png

  • 如果这部分的解析还是不清楚的话可以先往下看,看完就明白了。
  1. 出栈
//删除数据,出栈
void SKPop(SK* ps)
{
    assert(ps);

    assert(ps->top>0);

    ps->top--;
}
  • 出栈也很简单,我们不需要对栈内元素做什么,我们直接更改下标就好了。让top–,因为我初始化top=0嘛。所以top就是栈顶元素的下一个元素的下标,也就是栈顶元素下标+1,top–之后,原本的栈顶就变成了新栈顶的下一个元素。后续插入数据也不会影响,会被直接覆盖。
  1. 获取现在栈顶元素的值
//获取现在栈顶元素的值
SKDataType SKTop(SK* ps)
{
    assert(ps);

    assert(ps->top>0);

    return ps->a[ps->top-1];
}
  • 这个也没什么好说的,top就是栈顶元素的下标+1,想要获得栈顶元素,top-1就可以了。
  1. 栈的大小(栈中含有的有效元素个数)
//栈的大小
int SKSize(SK* ps)
{
    assert(ps);

    return ps->top;
}
  • 因为我初始化top=0,每次插入元素,top就+1,所以top的大小也是有效元素的大小。
  1. 判断栈是否为空
//判断栈是否为空
bool SKEmpty(SK* ps)
{
    assert(ps);

    return ps->top==0;
}
  • 因为我初始化top=0,这个就标志了栈是没有元素的。和上面计算栈的大小差不多,每次插入元素top+1,所以就可以直接用top==0来判断了。返回的是bool类型,记得带上stdbool.h头文件。
  1. 测试函数说明
#include "stack.h"

void TestStack1()
{
    SK st;
    SKInit(&st);
    SKPush(&st, 1);
    SKPush(&st, 2);
    SKPush(&st, 3);
    SKPush(&st, 4);
    SKPush(&st, 5);

    while (!SKEmpty(&st))
    {
        printf("%d ", SKTop(&st));
        SKPop(&st);
    }
    printf("\n");

    SKDestroy(&st);
}

int main()
{
    TestStack1();

    return 0;
}

https://i-blog.csdnimg.cn/direct/363348c7edab4741a115769d86bd751a.png

  • 那么栈的内容就大概讲完了。后面会给大家讲道题,帮助大家感受一下,栈的作用。