【数据结构】栈

目录

一、生活中的栈:叠盘子的启示

二、栈的基本概念

2.1 栈是什么

2.2 栈的特性:后进先出(LIFO)

三、栈的实现方式

3.1 数组实现栈

3.1.1 栈的结构定义

3.1.2 初始化栈

3.1.3 入栈操作

3.1.4 出栈操作

3.1.5 获取栈顶元素

3.1.7 判断栈是否为空

3.1.8 获取栈中元素个数

3.2 链表实现栈(简单提及)

四、栈的应用场景

4.1 函数调用栈

4.2 表达式求值

4.3 括号匹配

4.4 浏览器的前进和后退功能

五、实际代码示例与演练

5.1 用 C 语言实现栈的完整代码

5.2 代码分析与调试

六、总结与拓展

6.1 总结栈的核心要点

6.2 拓展思考


一、生活中的栈:叠盘子的启示

        在深入探索数据结构中的栈之前,让我们先把目光投向日常生活中一个再熟悉不过的场景 —— 叠盘子。想象一下,饭后收拾餐具,你将洗净的盘子一个个叠放在一起。最先放上去的盘子,被压在了最底层;而最后放上去的盘子,稳稳地处在最顶端。当需要取用盘子时,你会从最上面开始拿取,最后才会用到最下面的那个盘子。这看似平常的叠盘子、取盘子过程,其实就蕴含着栈的核心特性 —— 后进先出(Last In First Out,LIFO) 。

        后进先出是栈的标志性特征,就像一个只允许单向进出的特殊容器,新元素总是从一端进入(入栈),而出栈时,也是从这一端取出元素,且最后进入的元素最先被取出。这种特性使得栈在处理数据时有着独特的优势,它可以有效地管理和存储那些需要按照特定顺序处理的数据,尤其是当数据的处理顺序与存储顺序相反时,栈就成为了理想的数据结构选择。

二、栈的基本概念

2.1 栈是什么

        在数据结构的世界里,栈是一种特殊的线性表。它就像一个只允许从一端进出的特殊容器,所有的操作都只能在这个特定的一端进行,这一端被称为 “栈顶” 。而另一端则是 “栈底”,栈底相对固定,不参与日常的插入和删除操作。 栈的操作主要有两种:入栈(Push)和出栈(Pop)。入栈,也叫进栈或压栈,是将新元素添加到栈顶的操作,就如同把一个新盘子叠放在已有的盘子最上面;出栈,也叫退栈,是从栈顶移除元素的操作,类似于从叠放的盘子中拿走最上面的那个盘子 。当栈中没有任何元素时,我们称它为空栈,就像一摞空的盘子架子。

2.2 栈的特性:后进先出(LIFO)

        栈最显著的特性就是后进先出(Last In First Out,LIFO),这是理解栈的关键。我们以一个简单的数字序列为例,假设有数字 1、2、3 依次入栈。首先,1 入栈,此时栈里只有 1;接着 2 入栈,2 位于栈顶,1 在栈底;然后 3 入栈,3 成为栈顶元素,2 和 1 依次在其下方。当进行出栈操作时,3 最先出栈,因为它是最后入栈的;接着是 2 出栈,最后是 1 出栈。这个过程清晰地展示了后进先出的特性,就像叠放和取用盘子一样,最后放上去的盘子最先被拿走 。

        后进先出的特性使得栈在很多场景下都有着独特的应用价值。比如在程序中处理函数调用时,函数的参数和局部变量就会按照后进先出的顺序被压入栈和弹出栈,确保函数的正确执行和返回 。再比如在表达式求值中,通过栈可以有效地处理运算符的优先级,保证计算结果的准确性 。

三、栈的实现方式

        栈作为一种重要的数据结构,在实际应用中有着广泛的用途。为了满足不同场景的需求,栈有多种实现方式,其中数组和链表是两种最常见的实现方式 ,它们各自有着独特的特点和适用场景。下面,让我们深入了解这两种实现方式。

3.1 数组实现栈

3.1.1 栈的结构定义

        使用数组实现栈时,我们可以定义一个结构体来表示栈。这个结构体通常包含以下几个成员:

typedef struct Stack {

int *data; // 存储栈中元素的数组

int top; // 栈顶指针,指向栈顶元素的位置

int capacity; // 栈的容量,即数组的大小

} Stack;

        在上述代码中,data是一个动态分配的数组,用于存储栈中的元素;top表示栈顶指针,它记录了当前栈顶元素在数组中的索引位置;capacity则表示栈的最大容量,即数组能够容纳的元素个数 。通过这种结构体定义,我们可以方便地管理和操作栈。

3.1.2 初始化栈

        初始化栈是使用栈的第一步,其主要作用是为栈分配内存空间,并设置初始状态。初始化函数的实现如下:

Stack* createStack(int capacity) {

Stack *stack = (Stack*)malloc(sizeof(Stack));

stack->data = (int*)malloc(capacity * sizeof(int));

stack->top = -1; // 初始化栈顶指针为-1,表示栈为空

stack->capacity = capacity;

return stack;

}

        在这个函数中,首先使用malloc函数为栈结构体和存储元素的数组分配内存空间。然后,将栈顶指针top初始化为 - 1,这是因为在数组中,-1 表示栈为空,此时栈中没有任何元素。最后,设置栈的容量为传入的参数capacity,这样就完成了栈的初始化 。

3.1.3 入栈操作

        入栈操作是将一个新元素添加到栈顶的过程。在进行入栈操作时,需要先检查栈是否已满,如果栈满,则需要进行扩容操作。入栈操作的实现代码如下:

void push(Stack *stack, int value) {

if (stack->top == stack->capacity - 1) {

// 栈满,进行扩容

stack->capacity *= 2;

stack->data = (int*)realloc(stack->data, stack->capacity * sizeof(int));

}

stack->data[++stack->top] = value; // 先将栈顶指针加1,然后将元素存入栈顶位置

}

        在上述代码中,首先判断栈是否已满,即stack->top是否等于stack->capacity - 1。如果栈满,则将栈的容量扩大为原来的 2 倍,并使用realloc函数重新分配内存空间 。然后,将栈顶指针stack->top加 1,使其指向新的栈顶位置,再将新元素value存入该位置,完成入栈操作。

3.1.4 出栈操作

        出栈操作是从栈顶移除元素的过程。在进行出栈操作时,需要先检查栈是否为空,如果栈空,则不能进行出栈操作。出栈操作的实现代码如下:

int pop(Stack *stack) {

if (stack->top == -1) {

// 栈空,抛出异常或返回错误值

printf("栈为空,无法出栈\n");

return -1;

}

return stack->data[stack->top--]; // 先返回栈顶元素,然后将栈顶指针减1

}

        在这段代码中,首先判断栈是否为空,即stack->top是否等于 - 1。如果栈空,则打印错误信息并返回 - 1,表示出栈失败 。否则,返回栈顶元素stack->data[stack->top],然后将栈顶指针stack->top减 1,使其指向新的栈顶位置,完成出栈操作。

3.1.5 获取栈顶元素

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大雨淅淅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值