使用栈实现简单计算器

简介: 使用栈实现简单计算器

利用栈实现简单计算器


数据结构之利用栈实现简单计算器-C语言代码实现: juejin.cn/post/705011…




1. 中缀表达式 和 后缀表达式


中缀表达式: 顾名思义,操作符在操作数的中间,例如: 1 + 1

后缀表达式: 指操作符在操作后后面 ,例如 1 1 + , 就代表 中缀表达式 的 1 + 1

关于具体的 请参考: baike.baidu.com/item/%E9%80…



2. 关于数据结构: 栈


栈就是一个先进先出的队列

C语言函数之间调用,就是使用栈进行的

参考:  baike.baidu.com/item/%E6%A0…



3. 中缀表达式 如何利用栈 转换为后缀表达式


利用栈转换规则如下


遍历中缀表达式


  1. 判断为 数字 直接输出
  2. 判断为 ( 入栈
  3. 判断为 ) 则,出栈 直至遇到 (
  4. 判断为 * 或 /
  • 4.1 判断栈顶元素是否是 * 或 / , 如果是 则出栈
    4.2 若1不符合规则,再将这个字符入栈
  1. 判断为 +- ,则
  • 5.1 判断栈顶元素是否是 * 或 / ,如果是,则全部出栈,然后再入栈
    5.2 若1不符合,再将这个字符入栈
  1. 若表达式计算完毕,将出栈所有数据





实际例子


通过栈,将式子 3+2(9+8)/3(3/5)** 转换为后缀表达式

开始式子: 3+2*(9+8)/3*(3/5)


开始处理: 3 执行规则1,是数字直接输出

输出: 3

:


开始处理: + 执行规则 5.2 直接入栈

输出: 3

: +


开始处理: 2 执行规则1,是数字直接输出

输出: 32

: +


开始处理: * 执行规则4.2,直接入栈

输出: 32

: +*


开始处理: ( 执行规则2,直接入栈

输出: 32

: +*(


开始处理: 9 执行规则1,直接入栈

输出: 329

: +*(


开始处理: + 执行规则5.2,直接入栈

输出: 329

: +*(+


开始处理: 8 执行规则1,直接入栈

输出: 3298

: +*(+


开始处理: ) 执行规则3,出栈直至遇到 (

输出: 3298+

: +*


开始处理: / 执行规则4.1,将栈顶元素为*或/直接出栈,然后在入栈该操作符

输出: 3298+*

: +/


开始处理: 3 执行规则1,直接入栈

输出: 3298+*3

: +/


开始处理: * 执行规则4.1,将栈顶元素为*或/直接出栈,然后在入栈该操作符

输出: 3298+*3/

: +*


开始处理: ( 执行规则2,直接入栈

输出: 3298+*3/

: +*(


开始处理: 3 执行规则1,直接入栈

输出: 3298+*3/3

: +*(


开始处理: / 执行规则4.2,入栈

输出: 3298+*3/3

: +*(/


开始处理: 5 执行规则1,直接入栈

输出: 3298+*3/35

: +*(/


开始处理: ) 执行规则3,出栈 直至遇到(

输出: 3298+*3/35/

: +*


开始处理: ) 执行规则6,全部出栈

输出: 3298+*3/35/*+

:


得到中缀表达式: 3298+*3/35/*+

完毕

转换代码 C语言实现:

# include <stdio.h>
int main() {
    // 中缀表达式
    char formula[] = "3+2*(9+8)/3*(3/5)";
    // 栈
    char options[sizeof(formula) * sizeof(char)];
    int stackLen = -1;
    printf("%s\n",formula);
    int i;
    for (i = 0; formula[i]!='\0'; i++) {
        // 规则1
        if (formula[i] >= '0' && formula[i] <= '9') {
            printf("%c",formula[i]);
        }
        switch (formula[i]) {
            // 规则2
            case '(': {
                stackLen += 1;
                options[stackLen] =formula[i];
                break;
            }
            // 规则3
            case ')': {
                while (stackLen >= 0 &&  (options[stackLen] != '(')) {
                    printf("%c",options[stackLen]);
                    stackLen -= 1;
                }
                stackLen-=1;
                break;
            }
            // 规则4
            case '*':
            case '/': {
                while (stackLen >= 0 && (options[stackLen] == '*' || options[stackLen] == '/')) {
                    printf("%c",options[stackLen]);
                    stackLen -= 1;
                }
                stackLen += 1;
                options[stackLen] = formula[i];
                break;
            }
            // 规则5
            case '+': 
            case '-': {
                if (stackLen >= 0 &&  (options[stackLen] == '*' || options[stackLen] == '/')) {
                    while (stackLen >= 0) {
                        printf("%c",options[stackLen]);
                        stackLen -= 1;
                    }
                }
                stackLen += 1;
                options[stackLen] = formula[i];
                break;
            }
        }
    }
    // 规则6 
    while (stackLen >= 0) {
        printf("%c",options[stackLen]);
        stackLen--;
    }
    printf("\n");
}


执行结果

# gcc calTest1.c
# ./a.out
3+2*(9+8)/3*(3/5)
3298+*3/35/*+
#






4. 利用栈 后缀表达式计算结果


利用栈计算后缀表达式规则如下


假设后缀表达式是有效的

遍历后缀表达式

  1. 判断为数字,则进行压栈
  2. 判断为操作符(+ - * /)
    2.1 出栈2个元素,m 和 n (对于当前栈而言,m: 栈顶元素 n: 栈顶第二个元素)
    2.2 计算 n 操作符 m ,然后将结果 入栈


实际例子

通过栈,将计算后缀表达式 3298+*3/35/*+ 的值

式子:  3298+*3/35/*+


开始处理: 3

执行规则1: 直接入栈

: 3


开始处理: 2

执行规则1: 直接入栈

: 3 2


开始处理: 9

执行规则1: 直接入栈

: 3 2 9


开始处理: 8

执行规则1: 直接入栈

: 3 2 9 8


开始处理: +

执行规则2: 取出2个元素, m:8 n:9 , 并且执行结果(n + m)入栈

: 3 2 17


开始处理: *

执行规则2: 取出2个元素, m:17 n:2 , 并且执行结果(n * m)入栈

: 3 34


开始处理: 3

执行规则1: 直接入栈

: 3 34 3


开始处理: /

执行规则2: 取出2个元素, m:3  n:34 , 并且执行结果(n / m)入栈

: 3 11.3


开始处理: 3

执行规则1: 直接入栈

: 3 11.3 3


开始处理: 5

执行规则1: 直接入栈

: 3 11.3 3 5


开始处理: /

执行规则2: 取出2个元素, m:5  n:3 , 并且执行结果(n / m)入栈

: 3 11.3 0.6


开始处理: *

执行规则2: 取出2个元素, m:0.6  n:11.3 , 并且执行结果(n * m)入栈

: 3 6.8


开始处理: +

执行规则2: 取出2个元素, m:6.8  n:3 , 并且执行结果(n + m)入栈

: 9.8


计算结果: 9.8


完成

用C实现该代码

转换代码 C语言实现:

# include <stdio.h>
int main() {
    // 后缀表达式
    char formula[] = "3298+*3/35/*+";
    // 栈
    float options[sizeof(formula) * sizeof(char)];
    int stackLen = -1;
    printf("%s\n",formula);
    int i;
    for(i=0;formula[i]!='\0';i++) {
        // 规则1
        if (formula[i] >= '0' && formula[i] <= '9') {
            stackLen++;
            options[stackLen] = (float)(formula[i]-48);
        } else {
            // 规则2
            float m = options[stackLen];
            stackLen--;
            float n = options[stackLen];
            stackLen--;
            switch (formula[i]) {
                case '*': {
                     stackLen++;
                     options[stackLen] = (n * m);
                     break;
                }
                case '/': {
                     stackLen++;
                     options[stackLen] = (n / m);
                     break;
                }
                case '+': {
                     stackLen++;
                     options[stackLen] = (n + m);
                     break;
                }
                case '-': {
                     stackLen++;
                     options[stackLen] = (n - m);
                     break;
                }
            }
        }
    }
    printf("\n结果为: %.2f\n" , options[0]);
}



执行结果

# ./a.out
3298+*3/35/*+
结果为: 9.80
#

相关文章
|
3月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
364 9
|
3月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
58 1
|
1月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
150 77
|
13天前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
1月前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
50 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
1月前
|
存储 C语言 C++
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
49 9
|
1月前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
43 7
|
3月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
103 5
|
3月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
124 21
|
3月前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。