数据结构–栈

数据结构--栈

什么是栈?

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

栈的实现

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

实现代码

  • 头文件.h
c 复制代码
#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
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(仅供参考)
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. 栈的结构
c 复制代码
//取别名,方便更换数据类型,比如你要存char类型数据的时候,直接把int换成char,就可以全局替换数据了
typedef int SKDataType;
typedef struct Stack
{
    SKDataType *a;
    int top;//标记栈顶的工具
    int capacity;//容量
}SK;
  1. 初始化栈
c 复制代码
//初始化栈
void SKInit(SK* ps)
{
    assert(ps);

    ps->a=NULL;
    ps->capacity=0;
    ps->top=0;
}
  1. 销毁栈
c 复制代码
//销毁栈
void SKDestroy(SK* ps)
{
    assert(ps);

    free(ps->a);
    ps->a=NULL;
    ps->top=ps->capacity=0;
}
  • 销毁栈就没什么好说的了,就是把结构体(工具包)里面的本体(数组/栈)给free掉(将动态开辟的空间返还给系统),指针置空,其他值也置为零。
  1. 压栈
c 复制代码
//插入数据,压栈
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++;
}
  • 如果这部分的解析还是不清楚的话可以先往下看,看完就明白了。
  1. 出栈
c 复制代码
//删除数据,出栈
void SKPop(SK* ps)
{
    assert(ps);

    assert(ps->top>0);

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

    assert(ps->top>0);

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

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

    return ps->top==0;
}
  • 因为我初始化top=0,这个就标志了栈是没有元素的。和上面计算栈的大小差不多,每次插入元素top+1,所以就可以直接用top==0来判断了。返回的是bool类型,记得带上stdbool.h头文件。
  1. 测试函数说明
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;
}
  • 那么栈的内容就大概讲完了。后面会给大家讲道题,帮助大家感受一下,栈的作用。
相关推荐
*.✧屠苏隐遥(ノ◕ヮ◕)ノ*.✧35 分钟前
C语言_数据结构总结6:链式栈
c语言·开发语言·数据结构·算法·链表·visualstudio·visual studio
于慨36 分钟前
数据结构(王卓版)
数据结构
田梓燊1 小时前
leetcode 95.不同的二叉搜索树 Ⅱ
数据结构·算法·leetcode
情深不寿3172 小时前
数据结构--AVL树
数据结构·c++
孑么4 小时前
力扣 编辑距离
java·数据结构·算法·leetcode·职场和发展·贪心算法·动态规划
手握风云-4 小时前
Java数据结构第二十期:解构排序算法的艺术与科学(二)
数据结构·算法·排序算法
开心比对错重要12 小时前
leetcode69.x 的平方根
数据结构·算法·leetcode
Doopny@13 小时前
数字组合(信息学奥赛一本通-1291)
数据结构·算法·动态规划
君莫愁。13 小时前
【Unity】搭建基于字典(Dictionary)和泛型列表(List)的音频系统
数据结构·unity·c#·游戏引擎·音频
原来是猿13 小时前
蓝桥备赛(13)- 链表和 list(上)
开发语言·数据结构·c++·算法·链表·list