表达式求值(中缀转后缀及后缀表达式求值)

表达式求值(中缀转后缀及后缀表达式求值)。中缀表达式转后缀表达式:中缀表达式转后缀表达式遵循以下原则:1.遇到操作数,直接输出;2.栈为空时,遇到运算符,入栈;3.遇到左括号,将其入栈;4.遇到右括号,执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出;5.遇到其他运算符’+”-”*”/’时,弹出所有优先级大于或等于该运

大家好,又见面了,我是你们的朋友全栈君。

。中缀表达式转后缀表达式:

中缀表达式转后缀表达式遵循以下原则:

1.遇到操作数,直接输出;
2.栈为空时,遇到运算符,入栈;
3.遇到左括号,将其入栈;
4.遇到右括号,执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出;
5.遇到其他运算符’+”-”*”/’时,弹出所有优先级大于或等于该运算符的栈顶元素,然后将该运算符入栈;
6.最终将栈中的元素依次出栈,输出。
经过上面的步骤,得到的输出既是转换得到的后缀表达式。
举例:a+b*c+(d*e+f)g ———> abc+de*f+g*+

图示上述过程:

因为比较懒,而刚好在网上看到画的还不错的图,所以就直接贴过来了哦。希望作者不要怪罪哦。。。
遇到a,直接输出:

这里写图片描述

遇到+,此时栈为空,入栈:
这里写图片描述

遇到b,直接输出:
这里写图片描述
遇到*,优先级大于栈顶符号优先级,入栈:
这里写图片描述

遇到c,输出:
这里写图片描述
到+,目前站内的与+优先级都大于或等于它,因此将栈内的,+依次弹出并且输出,并且将遇到的这个+入栈:
这里写图片描述
遇到(,将其入栈:
这里写图片描述

遇到d,直接输出:
这里写图片描述
遇到*,由于的优先级高于处在栈中的(,因此入栈:
这里写图片描述
遇到e,直接输出:
这里写图片描述
遇到+,栈顶的优先级高于+,但是栈内的(低于+,将出栈输出,+入栈:这里写图片描述

遇到f,直接输出:
这里写图片描述
遇到),弹出栈顶元素并且输出,直到弹出(才结束,在这里也就是弹出+输出,弹出(不输出:
这里写图片描述
遇到*,优先级高于栈顶+,将*入栈
这里写图片描述
遇到g,直接输出: :
这里写图片描述
此时已经没有新的字符了,依次出栈并输出操作直到栈为空:
这里写图片描述

因为后缀表达式求值过程较为简单:
所以在这里我只进行简单说明:
1.扫描后缀表达式:
①如果是数字,则让其进栈
②若为操作符,则从栈中取出两个操作数,先取出的作为右操作数,后取出的作为左操作数,然后进行该操作符的运算,并使其结果入栈。
③重复上述过程,直至表达式扫描完成。
2.最终栈中只留一个元素—–>即就是结果。

下面代码实现中缀转后缀以及后缀表达式求值:

使用的栈是自定义栈(自己实现的):
//stack.h

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include<cassert>

//------------使用类型萃取来拷贝栈内元素-------------
struct _TrueType
{
    bool Get()
    {
        return true;
    }
};

struct _FalseType
{
    bool Get()
    {
        return false;
    }
};

template<class _Tp>
struct TypeTraits
{
    typedef _FalseType _IsPODType;
};

template<>
struct TypeTraits<bool>
{
    typedef _TrueType _IsPODType;
};

template<>
struct TypeTraits<int>
{
    typedef _TrueType _IsPODType;
};

template<>
struct TypeTraits<unsigned int>
{
    typedef _TrueType _IsPODType;
};

template<>
struct TypeTraits<char>
{
    typedef _TrueType _IsPODType;
};

template<>
struct TypeTraits< float >
{
    typedef _TrueType _IsPODType;
};

template<>
struct TypeTraits< double >
{
    typedef _TrueType _IsPODType;
};

template<>
struct TypeTraits<long>
{
    typedef _TrueType _IsPODType;
};

template<>
struct TypeTraits< unsigned long>
{
    typedef _TrueType _IsPODType;
};

template<class T>
void Copy(T* dst, T* src, size_t size)
{
    if (TypeTraits<T>::_IsPODType().Get())
    {
        memcpy(dst, src, size);
    }
    else
    {
        for (int i = 0; i < size; ++i)
        {
            dst[i] = src[i];
        }
    }
}

template<class T>
struct TypeTraits< T* >
{
    typedef _TrueType _IsPODype;
};

//-------------------------栈的基本操作----------------
template<class T>
class Stack
{
public:
    //构造函数
    Stack(int capacity = 10)
        :_pData(NULL)
        , _capacity(capacity)
        , _size(0)
    {
        _pData = new T[capacity];
    }

    //拷贝构造函数
    Stack(const Stack<T>& s)
        :_pData(new T[s._capacity])
        , _size(s._size)
        , _capacity(s._capacity)
    {
        for (int i = 0; i < _size; ++i)
        {
            _pData[i] = s._pData[i];
        }
    }

    //赋值运算符函数
    Stack& operator=(Stack<T> s)
    {
        std::swap(_pData, s._pData);
        _size = s._size;
        _capacity = s._capacity;
        return *this;
    }

    //入栈
    void Push(const T& data)
    {
        CheckCapacity();
        _pData[_size++] = data;
    }
    //出栈
    void Pop()
    {
        if (!Empty())
        {
            --_size;
        }
    }

    //获取栈顶元素
    T& Top()
    {
        if (!Empty())
        {
            return _pData[_size - 1];
        }
    }

    const T& Top()const
    {
        if (!Empty())
        {
            return _pData[_size - 1];
        }
    }

    size_t Size()const
    {
        return _size;
    }

    bool Empty()const
    {
        return 0 == _size;
    }

    //析构函数(释放资源)
    ~Stack()
    {
        if (_pData)
        {
            delete[] _pData;
            _pData = NULL;
        }
    }

private:
    //增容
    void CheckCapacity()
    {
        if (_size >= _capacity)
        {
            _capacity = 2 * _capacity + 3;
            T* tmp = new T[_capacity];
            //拷贝原数据
            //释放旧空间
            //指向新空间
           //需要进行类型萃取
            Copy<T>(_pData, tmp, _size);
            delete[] _pData;
            _pData = tmp;
        }
    }

    T* _pData;
    int _capacity;
    int _size;
};

//----------------------------------------------------------
//需要用到的函数的声明
int GetPriority(char ch, int flag);//获取优先级
bool IsOperator(char ch);//判断是否为操作符
void prefixionToSuffix(char* dst, char* src);//中缀表达式转后缀表达式
int  SuffixToValue(char *suffix, char *prefixion);//后缀表达式求值


中缀表达式转后缀表达式:
//prefixionToSuffix.cpp

#include"Stack.h"

//flag为1时表示栈内优先级  flag为0表示栈外优先级
int GetPriority(char ch, int flag)
{
    if (ch == '+' || ch == '-')
    {
        if (flag)
        {
            return 3;
        }
        else
        {
            return 2;
        }
    }
    else if (ch == '*' || ch == '/' || ch == '%')
    {
        if (flag)
        {
            return 5;
        }
        else
        {
            return 4;
        }
    }
    else if (ch == '(')
    {
        if (flag)
        {
            return 1;
        }
        return 6;
    }
    else if (ch == ')')
    {
        if (flag)
        {
            return 6;
        }
        else
        {
            return 1;
        }
    }
}

bool IsOperator(char ch)
{
    if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' || ch == '(' || ch == ')')
    {
        return true;
    }
    return false;
}

//中缀表达式转后缀表达式
void prefixionToSuffix(char* dst, char* src)
{
    assert(dst);
    assert(src);
    Stack<char> s;
    char * cur = src;
    char* tmp = dst;
    while (*cur != '\0')
    {
        if (*cur >= '0' && *cur <= '9')
        {
            *tmp++ = *cur;
            cur++;
            continue;
        }
        else if (IsOperator(*cur))
        {
            if (s.Empty())//如果栈为空,直接入栈
            {
                s.Push(*cur);
                cur++;
            }
            else//如果栈不空,则需要判断栈顶元素和当前操作符的优先级
            {
                if (*cur == ')')
                {
                    while (*cur == ')' && s.Top() != '(')
                    {
                        *tmp++ = s.Top();
                        s.Pop();
                    }
                    s.Pop();
                    cur++;
                }
                if (GetPriority(*cur, 0) > GetPriority(s.Top(), 1))
                {
                    s.Push(*cur);
                    cur++;
                }
                else
                {
                    while (!s.Empty() && GetPriority(*cur, 0) < GetPriority(s.Top(), 1))
                    {
                        *tmp++ = s.Top();
                        s.Pop();
                    }
                    s.Push(*cur);
                    cur++;
                }

            }
        }
        else
        {
            *tmp++ = *cur++;
        }
    }
    while(!s.Empty())
    {
        *tmp++ = s.Top();
        s.Pop();
    }
}

后缀表达式求值:
//SuffixToValue.cpp

#include"Stack.h"

//12 3 4 + * 6 - 8 2 / +
int  SuffixToValue(char *suffix, char *prefixion)
{
    prefixionToSuffix(suffix, prefixion);

    Stack<int> s;
    char* cur = suffix;
    int res = 0;
    int tmp = 0;
    while (*cur != '\0')
    {
        if (*cur == '+' || *cur == '-' || *cur == '*' || *cur == '/' || *cur == '%')
        {
            char ch = *cur;
            int right = s.Top();
            s.Pop();
            int left = s.Top();
            s.Pop();
            switch (ch)
            {
            case '+':
                s.Push(left + right);
                break;
            case '-':
                s.Push(left - right);
                break;
            case '*':
                s.Push(left * right);
                break;
            case '%':
                s.Push(left % right);
                break;
            case '/':
                if (right)
                {
                    s.Push(left / right);
                }
                break;
            }
            cur++;
        }
        else if (*cur >= '0' && *cur <= '9')
        {
            res = 0;
            while (!isspace(*cur) && *cur >= '0' && *cur <= '9')
            {
                tmp = *cur - '0';
                res = res * 10 + tmp;
                cur++;
            }
            s.Push(res);
            //cur++;
        }
        else
        {
            cur++;
        }
    }
    if (!s.Empty())
    {
        res = s.Top();
        return res;
    }
}

main.cpp

#include"Stack.h"

void Test()
{
    char prefixion[] = "12 * (3 + 4) - 6 + 8 / 2 ";//保存前缀表达式
    char suffix[25] = {};//保存后缀表达式
    int res = SuffixToValue(suffix, prefixion);
    cout << res << endl;
}

int main()
{
    Test();
    return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/149735.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Spring Cloud的架构[通俗易懂]

    Spring Cloud的架构[通俗易懂]SpringCloud架构图Eureka用于服务注册和发现,利用了客户端的服务发现,所以它内部需要Ribbon作为客户端负载均衡。Hystrix,客户端容错保护,服务熔断、请求缓存、请求合并、依赖隔离。Feign,声明式服务调用。Bus,消息总线,配合Config仓库修改的一种Stream实现,Dashboard,Hystrix仪表盘,监控集群模式和单点模式,其中集群模式…

    2022年5月13日
    34
  • 自己搭建git服务器_搭建git服务器web界面

    自己搭建git服务器_搭建git服务器web界面docker安装gitea服务器1.安装docker:yuminstalldocker-y2.启动docker服务:systemctlstartdocker3.查看docker版本:docker-v4.配置镜像加速:vi/etc/docker/deamon.json修改内容{ “registry-mirrors”:[ “http://reg-mirror.qiniu.com/”, “http://hub-mirror.c.163.com/” ]}5

    2022年10月5日
    2
  • 微信电脑版打不开怎么办?电脑版微信打不开的解决方案_wechatwin.dll文件缺失怎么解决

    微信电脑版打不开怎么办?电脑版微信打不开的解决方案_wechatwin.dll文件缺失怎么解决微信现在除了是日常的交流工具,基本上办公也离不开它,微信也注意到大家的意愿,所以也开发了电脑端的微信,不过有时候电脑版的微信也不好用,遇到紧急情况需要通知同事的时候又发现打不开了,通常遇上这种情况,我们要采取这些措施。解决办法如下:电脑版微信打不开是怎么一回事?第一步要做的就是,排查网络或是电脑系统的问题,可以重启试试。排除电脑或者网络问题以后,那可能是微信客户端不稳定。也许是文件损坏了或者是系统…

    2022年8月12日
    4
  • 【笔试题】2019海康威视嵌入式软件开发工程师(BSP)笔试题(附超详细解答)「建议收藏」

    【笔试题】2019海康威视嵌入式软件开发工程师(BSP)笔试题(附超详细解答)「建议收藏」海康威视嵌入式软件工程师的题目只包含两个部分选择题和简答题,也就是说,没有编程题!照样是C语言基础的题量最多了,又因为是BSP方向,所以关于Linux操作系统和驱动方面的题目可能页会比较多一点,但是就题目的总体难度而言,也并不是特别难。但如果对Linux、驱动方面不是很了解的话,估计会很吃亏的。选择题1、若有8个待排序元素,采用冒泡排序和插入排序最大时间复杂度分别是()。64…

    2022年6月24日
    46
  • 如何分析heapdump文件_heapdump怎么看

    如何分析heapdump文件_heapdump怎么看jhat是Java堆分析工具(JavaheapAnalyzesTool).在JDK6u7之后成为标配.使用该命令需要有一定的Java开发经验,官方不对此工具提供技术支持和客户服务。用法:jhat[options]heap-dump-file参数:options可选命令行参数,请参考下面的Optionsheap-dump-file要查看的二进制Java堆转储文件(Java…

    2022年10月3日
    5
  • goland 2021.4 激活码_通用破解码

    goland 2021.4 激活码_通用破解码,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月17日
    85

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号