栈应用——逆波兰算法

简介: 栈应用——逆波兰算法

前言


在我们进行数字运算时我们会根据优先级自然的将结果算出来如同喝水一样,这是因为我们在学习算数开始就已经对这种运算方式习以为常了,但只能分辨出0和1的计算机又是如何进行运算的呢?🤔🤔🤔


中缀表达式?


例如a+b,运算符在两个操作数的中间。这是我们一直习惯使用的表达式形式


后缀表达式


例如a b + ,运算符在两个操作数的后面。这是一种利于计算机处理的表达形式


逆波兰表达式(中缀表达式转后缀表达式)


逆波兰表达式又叫做后缀表达式。在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,这种表示法也称为中缀表示。波兰逻辑学家J.Lukasiewicz于1929年提出了另一种表示表达式的方法,按此方法,每一运算符都置于其运算对象之后,故称为后缀表示。


为啥要使用逆波兰表达式


逆波兰表达式是一种十分有用的表达式,它将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式。例如(a+b)(c+d)转换为ab+cd+

去除原来表达式中的括号,因为括号只指示运算顺序,不是实际参与计算的元素。

使得运算顺序有规律可寻,计算机能编写出代码完成计算。


1684813943521.png



实现原理


一、如果输入的是操作数,则直接追加入。当输入的是 运算符 或者 分界符时压入栈中

1. 如果是左括号 ‘(’, 则 直接压入栈中,等待下一个最近的 右括号 与之配对。

2. 如果是右括号 ‘)’,则说明有一对括号已经配对(在表达式输入无误的情况下)。那我们就不将它压栈,而是直接将它丢弃😶‍🌫️,然后出栈,得到元素d,将d依次运算。一直循环,直到出栈元素d 是 左括号 ( ,我们同样丢弃他。

(3)如果是运算符

1.如果栈顶元素不是运算符,则二者没有可比性,则直接将此运算符压栈。 例如栈顶是左括号 ( ,或者栈为空。

2.如果栈顶元素是运算符 ,则比较进入的运算符和栈顶运算符的优先级。如果进入运算符 > 栈顶运算符 ,则直接将此运算符压栈。

如果不满足,则将栈顶运算符出栈,再试图将运算符压栈,如果如果依然不满足 ,继续将新的栈顶运算符弹出 ,直到该运算符可以压入栈中为止。

也就是说,如果在栈中,有2个相邻的元素都是运算符,则他们必须满足:下层运算符的优先级一定小于上层元素的优先级,才能相邻。

最后,如果栈中还有元素,则依次弹出追加到d后,就得到了后缀表达式。


代码实现


#include <ctype.h>
#define STACK_INIT_SIZE 20 //栈的初始化空间大小
#define STACKINCREMENT        10 //每次增加的栈空间大小
#define MAXBUFFER                10 //缓冲区大小
typedef double ElemType;
typedef struct
{
    int stackSize;
    ElemType* base;//指向栈底的指针
    ElemType* top;//指向栈顶的指针
}sqStack;
void initStack(sqStack* s)
{
    s->base = (ElemType*)malloc(STACK_INIT_SIZE * sizeof(ElemType));
    if (!s->base)
    {
        exit(0);
    }
    s->top = s->base;
    s->stackSize = STACK_INIT_SIZE;
}
void Push(sqStack* s, ElemType e)//进栈
{
    if (s->top - s->base >= s->stackSize)
    {
        s->base = (ElemType*)realloc(s->base, (s->stackSize + STACKINCREMENT) * sizeof(ElemType));
        if (!s->base)
        {
            exit(0);
        }
        s->top = s->base + s->stackSize;
        s->stackSize = s->stackSize + STACK_INIT_SIZE;//大小要更新,不然会误认为容量不够又继续申请内存
    }
    *(s->top) = e;//把e对应的元素压入栈顶
    s->top++;//栈顶上移
}
void Pop(sqStack* s, ElemType* e)//出栈
{
    if (s->top == s->base)//判断栈是不是空
    {
        return;
    }
    *e = *--(s->top);
}
int stackLen(sqStack s)//计算栈的当前容量,s.stackSize
{
    return (s.top - s.base);
}
int main()
{
    char c;
    sqStack s;
    int i = 0;
    double d, e;//临时变量
    char str[MAXBUFFER];//小数存放缓冲区
    initStack(&s);
    printf("请输入逆波兰表达式,数据与运算符之间用空格隔开,按#键结束!\n");
    scanf("%c", &c);
    while (c != '#')
    {
        while (isdigit(c) || c == '.')//判断c是数字,头文件ctype.h,过滤数字和点以外的数据
        {
            str[i++] = c;
            str[i] = '\0';//给不知道下一个是否还要字符的位置赋结束符,以免不知道多长
            if (i >= MAXBUFFER)//字符串溢出
            {
                printf("\n出错:输入的单个数据过长!\n");
                return -1;
            }
            scanf("%c", &c);//继续输入数据
            if (c == ' ')//输入空格,代表单个数据输入结束
            {
                d = atof(str);//把字符串str转化为浮点数
                Push(&s, d);
                i = 0;//i初始化,进入下一个循环
                break;
            }
        }
        switch (c)
        {
        case '+'://两个出栈,并相加
            Pop(&s, &e);//出栈第一个数,给e
            Pop(&s, &d);//出栈第二个数,给d
            Push(&s, d + e);
            break;
        case '-'://两个出栈,并相减
            Pop(&s, &e);//出栈第一个数,给e
            Pop(&s, &d);//出栈第二个数,给d
            Push(&s, d - e);
            break;
        case '*'://两个出栈,并相乘
            Pop(&s, &e);//出栈第一个数,给e
            Pop(&s, &d);//出栈第二个数,给d
            Push(&s, d * e);
            break;
        case '/'://两个出栈,并相除
            Pop(&s, &e);//出栈第一个数,给e
            Pop(&s, &d);//出栈第二个数,给d
            if (e != 0)
            {
                Push(&s, d / e);
            }
            else
            {
                printf("\n错误:除数为零!\n");
                return -1;
            }
            break;
        }
        scanf("%c", &c);
    }
    Pop(&s, &d);//最终的结算结果放在d里
    printf("计算结果为:%f\n", d);
    return 0;
}
目录
相关文章
|
1月前
|
存储 监控 JavaScript
基于布隆过滤器的 Node.js 算法在局域网电脑桌面监控设备快速校验中的应用研究
本文探讨了布隆过滤器在局域网电脑桌面监控中的应用,分析其高效空间利用率、快速查询性能及动态扩容优势,并设计了基于MAC地址的校验模型,提供Node.js实现代码,适用于设备准入控制与重复数据过滤场景。
68 0
|
9天前
|
机器学习/深度学习 资源调度 算法
遗传算法模型深度解析与实战应用
摘要 遗传算法(GA)作为一种受生物进化启发的优化算法,在复杂问题求解中展现出独特优势。本文系统介绍了GA的核心理论、实现细节和应用经验。算法通过模拟自然选择机制,利用选择、交叉、变异三大操作在解空间中进行全局搜索。与梯度下降等传统方法相比,GA不依赖目标函数的连续性或可微性,特别适合处理离散优化、多目标优化等复杂问题。文中详细阐述了染色体编码、适应度函数设计、遗传操作实现等关键技术,并提供了Python代码实现示例。实践表明,GA的成功应用关键在于平衡探索与开发,通过精心调参维持种群多样性同时确保收敛效率
48 7
|
9天前
|
机器学习/深度学习 边缘计算 人工智能
粒子群算法模型深度解析与实战应用
蒋星熠Jaxonic是一位深耕智能优化算法领域多年的技术探索者,专注于粒子群优化(PSO)算法的研究与应用。他深入剖析了PSO的数学模型、核心公式及实现方法,并通过大量实践验证了其在神经网络优化、工程设计等复杂问题上的卓越性能。本文全面展示了PSO的理论基础、改进策略与前沿发展方向,为读者提供了一份详尽的技术指南。
27 0
粒子群算法模型深度解析与实战应用
|
9天前
|
机器学习/深度学习 算法 安全
小场景大市场:猫狗识别算法在宠物智能设备中的应用
将猫狗识别算法应用于宠物智能设备,是AIoT领域的重要垂直场景。本文从核心技术、应用场景、挑战与趋势四个方面,全面解析这一融合算法、硬件与用户体验的系统工程。
|
2月前
|
机器学习/深度学习 人工智能 算法
AI-Compass 强化学习模块:理论到实战完整RL技术生态,涵盖10+主流框架、多智能体算法、游戏AI与金融量化应用
AI-Compass 强化学习模块:理论到实战完整RL技术生态,涵盖10+主流框架、多智能体算法、游戏AI与金融量化应用
|
2月前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习模型、算法与应用的全方位解析
深度学习,作为人工智能(AI)的一个重要分支,已经在多个领域产生了革命性的影响。从图像识别到自然语言处理,从语音识别到自动驾驶,深度学习无处不在。本篇博客将深入探讨深度学习的模型、算法及其在各个领域的应用。
442 3
|
2月前
|
存储 监控 安全
企业上网监控系统中红黑树数据结构的 Python 算法实现与应用研究
企业上网监控系统需高效处理海量数据,传统数据结构存在性能瓶颈。红黑树通过自平衡机制,确保查找、插入、删除操作的时间复杂度稳定在 O(log n),适用于网络记录存储、设备信息维护及安全事件排序等场景。本文分析红黑树的理论基础、应用场景及 Python 实现,并探讨其在企业监控系统中的实践价值,提升系统性能与稳定性。
66 1
|
1月前
|
算法 数据可视化
matlab版本粒子群算法(PSO)在路径规划中的应用
matlab版本粒子群算法(PSO)在路径规划中的应用
|
2月前
|
存储 监控 算法
公司员工泄密防护体系中跳表数据结构及其 Go 语言算法的应用研究
在数字化办公中,企业面临员工泄密风险。本文探讨使用跳表(Skip List)数据结构优化泄密防护系统,提升敏感数据监测效率。跳表以其高效的动态数据处理能力,为企业信息安全管理提供了可靠技术支持。
51 0

热门文章

最新文章