栈应用——逆波兰算法

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

前言


在我们进行数字运算时我们会根据优先级自然的将结果算出来如同喝水一样,这是因为我们在学习算数开始就已经对这种运算方式习以为常了,但只能分辨出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;
}
目录
相关文章
|
4天前
|
存储 负载均衡 算法
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
35 15
|
10天前
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
|
5天前
|
存储 人工智能 算法
通过Milvus内置Sparse-BM25算法进行全文检索并将混合检索应用于RAG系统
阿里云向量检索服务Milvus 2.5版本在全文检索、关键词匹配以及混合检索(Hybrid Search)方面实现了显著的增强,在多模态检索、RAG等多场景中检索结果能够兼顾召回率与精确性。本文将详细介绍如何利用 Milvus 2.5 版本实现这些功能,并阐述其在RAG 应用的 Retrieve 阶段的最佳实践。
通过Milvus内置Sparse-BM25算法进行全文检索并将混合检索应用于RAG系统
|
12天前
|
存储 缓存 监控
企业监控软件中 Go 语言哈希表算法的应用研究与分析
在数字化时代,企业监控软件对企业的稳定运营至关重要。哈希表(散列表)作为高效的数据结构,广泛应用于企业监控中,如设备状态管理、数据分类和缓存机制。Go 语言中的 map 实现了哈希表,能快速处理海量监控数据,确保实时准确反映设备状态,提升系统性能,助力企业实现智能化管理。
27 3
|
22天前
|
算法 Serverless 数据处理
从集思录可转债数据探秘:Python与C++实现的移动平均算法应用
本文探讨了如何利用移动平均算法分析集思录提供的可转债数据,帮助投资者把握价格趋势。通过Python和C++两种编程语言实现简单移动平均(SMA),展示了数据处理的具体方法。Python代码借助`pandas`库轻松计算5日SMA,而C++代码则通过高效的数据处理展示了SMA的计算过程。集思录平台提供了详尽且及时的可转债数据,助力投资者结合算法与社区讨论,做出更明智的投资决策。掌握这些工具和技术,有助于在复杂多变的金融市场中挖掘更多价值。
47 12
|
20天前
|
算法 安全 网络安全
基于 Python 的布隆过滤器算法在内网行为管理中的应用探究
在复杂多变的网络环境中,内网行为管理至关重要。本文介绍布隆过滤器(Bloom Filter),一种高效的空间节省型概率数据结构,用于判断元素是否存在于集合中。通过多个哈希函数映射到位数组,实现快速访问控制。Python代码示例展示了如何构建和使用布隆过滤器,有效提升企业内网安全性和资源管理效率。
49 9
|
13天前
|
算法 安全 Java
探讨组合加密算法在IM中的应用
本文深入分析了即时通信(IM)系统中所面临的各种安全问题,综合利用对称加密算法(DES算法)、公开密钥算法(RSA算法)和Hash算法(MD5)的优点,探讨组合加密算法在即时通信中的应用。
15 0
|
21天前
|
机器学习/深度学习 人工智能 自然语言处理
解锁机器学习的新维度:元学习的算法与应用探秘
元学习作为一个重要的研究领域,正逐渐在多个应用领域展现其潜力。通过理解和应用元学习的基本算法,研究者可以更好地解决在样本不足或任务快速变化的情况下的学习问题。随着研究的深入,元学习有望在人工智能的未来发展中发挥更大的作用。
|
3月前
|
算法
【算法】栈
栈相关算法题,供参考,附有链接地址及板书
|
3月前
|
存储 缓存 算法
探索企业文件管理软件:Python中的哈希表算法应用
企业文件管理软件依赖哈希表实现高效的数据管理和安全保障。哈希表通过键值映射,提供平均O(1)时间复杂度的快速访问,适用于海量文件处理。在Python中,字典类型基于哈希表实现,可用于管理文件元数据、缓存机制、版本控制及快速搜索等功能,极大提升工作效率和数据安全性。
86 0