c语言利用栈实现表达式求值_C语言实现顺序栈以及栈的特点

什么是栈?

同顺序表和链表一样,栈也是用来存储逻辑关系为 "一对一" 数据的线性存储结构,如下图所示。

79bef22b0b3110a7fbce1d038eed43dc.png

从上图我们看到,栈存储结构与之前所学的线性存储结构有所差异,这缘于栈对数据 "存" 和 "取" 的过程有特殊的要求:

  1. 栈只能从表的一端存取数据,另一端是封闭的,如上图所示;
  2. 在栈中,无论是存数据还是取数据,都必须遵循"先进后出"的原则,即最先进栈的元素最后出栈。拿上图的栈来说,从图中数据的存储状态可判断出,元素 1 是最先进的栈。因此,当需要从栈中取出元素 1 时,根据"先进后出"的原则,需提前将元素 3 和元素 2 从栈中取出,然后才能成功取出元素 1。 因此,我们可以给栈下一个定义,即栈是一种只能从表的一端存取数据且遵循 "先进后出" 原则的线性存储结构。

通常,栈的开口端被称为栈顶;相应地,封口端被称为栈底。因此,栈顶元素指的就是距离栈顶最近的元素,拿下图来说,栈顶元素为元素 4;同理,栈底元素指的是位于栈最底部的元素,下图中的栈底元素为元素。

d47b7d7338f339f2b046b1f76951a476.png

进栈和出栈

基于栈结构的特点,在实际应用中,通常只会对栈执行以下两种操作: - 向栈中添加元素,此过程被称为"进栈"(入栈或压栈); - 从栈中提取出指定元素,此过程被称为"出栈"(或弹栈);

栈的具体实现

栈是一种 "特殊" 的线性存储结构,因此栈的具体实现有以下两种方式: 1. 顺序栈:采用顺序存储结构可以模拟栈存储数据的特点,从而实现栈存储结构; 2. 链栈:采用链式存储结构实现栈结构;

两种实现方式的区别,仅限于数据元素在实际物理空间上存放的相对位置,顺序栈底层采用的是数组,链栈底层采用的是链表。有关顺序栈和链栈的具体实现会在后续章节中作详细讲解。

顺序栈基本操作

顺序栈,即用顺序表实现栈存储结构。通过前面介绍我们知道,使用栈存储结构操作数据元素必须遵守 "先进后出" 的原则,下面就 "如何使用顺序表模拟栈以及实现对栈中数据的基本操作(出栈和入栈)" 给大家做一些介绍。

如果你仔细观察顺序表(底层实现是数组)和栈结构就会发现,它们存储数据的方式高度相似,只不过栈对数据的存取过程有特殊的限制,而顺序表没有。

例如,我们先使用顺序表(a 数组)存储{1,2,3,4},存储状态如下图所示:

2d6f2010350972b3d30eb50238c52cce.png

同样,使用栈存储结构存储{1,2,3,4},其存储状态如下图所示:

74113aae98ac56fc6f37b7ef1c3593e7.png

通过上面两张图对比不难看出,使用顺序表模拟栈结构很简单,只需要将数据从 a 数组下标为 0 的位置依次存储即可。

从数组下标为 0 的模拟栈存储数据是常用的方法,从其他数组下标处存储数据也完全可以,这里只是为了方便初学者理解。

了解了顺序表模拟栈存储数据后,接下来看如何模拟栈中元素出栈的操作。由于栈对存储元素出栈的次序有"先进后出"的要求,如果想将图中存储的元素 1 从栈中取出,需先将元素 4、元素 3 和元素 2 依次从栈中取出。

这里给出使用顺序表模拟栈存储结构常用的实现思路,即在顺序表中设定一个实时指向栈顶元素的变量(一般命名为 top),top 初始值为 -1,表示栈中没有存储任何数据元素,及栈是"空栈"。一旦有数据元素进栈,则 top 就做 +1 操作;反之,如果数据元素出栈,top 就做 -1 操作。

顺序栈元素"入栈"

比如,还是模拟栈存储{1,2,3,4} 的过程。最初,栈是"空栈",即数组是空的,top 值为初始值 -1,如下图所示:

be50e157120851fa093a0ce98d54b4cd.png

首先向栈中添加元素 1,我们默认数组下标为 0 一端表示栈底,因此,元素 1 被存储在数组 a[1] 处,同时 top 值 +1,如下图所示:

c6e61d8c061dd51732824ba4737034b4.png

采用以上的方式,依次存储元素 2、3 和 4,最终,top 值变为 3,如下图所示:

7f53f63995369919c4dd21ab0b1a0947.png

因此,C 语言实现代码为:

//元素elem进栈,a为数组,top值为当前栈的栈顶位置
int push(int* a,int top,int elem){
    a[++top]=elem;
    return top;
}

代码中的 a[++top]=elem,等价于先执行 ++top,再执行 a[top]=elem。

顺序栈元素"出栈"

其实,top 变量的设置对模拟数据的 "入栈" 操作没有实际的帮助,它是为实现数据的 "出栈" 操作做准备的。

比如,将上图中的元素 2 出栈,则需要先将元素 4 和元素 3 依次出栈。需要注意的是,当有数据出栈时,要将 top 做 -1 操作。因此,元素 4 和元素 3 出栈的过程分别如下图a) 和 下图b) 所示:

01191fffeefeb9ba4a7ee8c4020163b4.png
注意,上图数组中元素的消失仅是为了方便初学者学习,其实,这里只需要对 top 值做 -1 操作即可,因为 top 值本身就表示栈的栈顶位置,因此 top-1 就等同于栈顶元素出栈。并且后期向栈中添加元素时,新元素会存储在类似元素 4 这样的旧元素位置上,将旧元素覆盖。

元素 4 和元素 3 全部出栈后,元素 2 才能出栈。因此,使用顺序表模拟数据出栈操作的 C 语言实现代码为:

//数据元素出栈
int pop(int * a,int top){
    if (top==-1) {
        printf("空栈");
        return -1;
    }
    printf("弹栈元素:%dn",a[top]);
    top--;
    return top;
}

代码中的 if 语句是为了防止用户做 "栈中已无数据却还要数据出栈" 的错误操作。代码中,关于对栈中元素出栈操作的实现,只需要 top 值 -1 即可。 {% note success %} 继续加油!

以上就是本次给大家分享的利用C语言简单的实现顺序栈以及向大家介绍了栈的特点,完整的代码已经上传到github,C语言实现顺序栈 欢迎大家Star ! 有什么写的不好的地方希望大家在评论区留言,我加以改正,我们一起交流,一起进步啊!

北徯的博客​www.xiangjunhong.com
c05d9a48897528161ee872ea27102ef9.png
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于顺序实现表达式解的C语言代码: ```c #include <stdio.h> #include <stdlib.h> #include <ctype.h> #define STACK_SIZE 50 typedef struct { int top; int data[STACK_SIZE]; } Stack; void init(Stack *s) { s->top = -1; } void push(Stack *s, int item) { if (s->top == STACK_SIZE - 1) { printf("Stack overflow!\n"); exit(1); } s->data[++s->top] = item; } int pop(Stack *s) { if (s->top == -1) { printf("Stack underflow!\n"); exit(1); } return s->data[s->top--]; } int empty(Stack *s) { return s->top == -1; } int evaluate(char *expr) { Stack s; init(&s); int i, op1, op2; char ch; for (i = 0; expr[i] != '\0'; i++) { ch = expr[i]; if (isdigit(ch)) { push(&s, ch - '0'); } else { op2 = pop(&s); op1 = pop(&s); switch (ch) { case '+': push(&s, op1 + op2); break; case '-': push(&s, op1 - op2); break; case '*': push(&s, op1 * op2); break; case '/': push(&s, op1 / op2); break; default: printf("Invalid operator!\n"); exit(1); } } } return pop(&s); } int main() { char expr[STACK_SIZE]; printf("Enter an expression: "); fgets(expr, STACK_SIZE, stdin); printf("Result: %d\n", evaluate(expr)); return 0; } ``` 该代码使用了一个`Stack`结构体来实现顺序,并提供了`init`、`push`、`pop`和`empty`等基本操作函数。在`evaluate`函数中,遍历表达式中的每个字符,如果是数字则入,如果是运算符则弹出顶的两个操作数进行运算,并将结果入。最后返回中剩余的唯一元素作为表达式。在`main`函数中,使用`fgets`函数从标准输入读入一个表达式,并输出其结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值