数据结构学习-后缀表达式计算

251 阅读2分钟

数据结构学习-后缀表达式计算

最近在学习程杰老师的《大话数据结构》,当读到栈那一节部分内容的时候,发现了一个很有趣的计算四则运算的方式:后缀表达式计算法,也叫作逆波兰式。是一种将运算符写在数字后面的一种表达式写法。

例如:9+(3-1)3+10/2,化为逆波兰式就是:931-3+102/+

我就尝试着用C#实现了一下,代码如下:

ps.大佬勿喷,我就是想体验一下这种写法,如果觉得我是在用高级语言做无用功,那就无用吧= =。

static void Main(string[] args)
{
    Console.WriteLine("请输入想要计算的复杂计算式");
    string inputStr = Console.ReadLine();
    if (string.IsNullOrWhiteSpace(inputStr))
    {
        Console.WriteLine("您没有输入任何表达式");
        return;
    }

    //获取后缀表达式
    var suffixStr = GetSuffixStr(inputStr);
    Console.WriteLine("后缀表达式为:" + suffixStr);

    //根据后缀表达式计算结果
    var result = GetResult(suffixStr);
    Console.WriteLine("计算结果为:" + result);

    Console.ReadKey();
}


/// <summary>
/// 获取后缀表达式
/// </summary>
/// <param name="expression">中缀表达式</param>
/// <returns></returns>
public static string GetSuffixStr(string expression)
{
    Stack<char> stack = new Stack<char>();

    //将中文算数操作符转换成英文操作符
    expression = ToDBC(expression);

    string suffixStr = string.Empty;

    foreach (char c in expression)
    {
        //如果是数字,则放置到结果字符串中
        if (char.IsDigit(c))
        {
            suffixStr += c;
            continue;
        }

        //如果是右括号 => 出栈
        if (c == ')')
        {
            //循环出栈,直至遇到'('
            while (stack.Peek() != '(')
            {
                suffixStr += stack.Pop();
            }

            //最后需要将对应的'('也出栈
            stack.Pop();    
        }
        //如果优先级小于栈顶元素 => 出栈
        else if (stack.Count != 0 && SetPriority(stack.Peek()) > SetPriority(c) && stack.Peek() != '(')   
        {
            //循环出栈,直至遇到'('或者全部出栈
            while (stack.Count != 0 && stack.Peek() != '(')
            {
                suffixStr += stack.Pop();
            }
        }
        else    //否则直接进栈
        {
            stack.Push(c);
        }
    }

    //字符串循环完毕,栈中剩余操作符依次出栈
    while (stack.Count != 0)
    {
        suffixStr += stack.Pop();
    }

    return suffixStr;
}


/// <summary>
/// 获取计算结果
/// </summary>
/// <param name="suffixStr">后缀表达式</param>
/// <returns></returns>
public static int GetResult(string suffixStr)
{
    Stack<int> stack = new Stack<int>();

    foreach (char c in suffixStr)
    {
        //如果是数字,则进栈
        if (char.IsDigit(c))
        {
            stack.Push(Convert.ToInt32(c.ToString()));
            continue;
        }
        //如果不是数字,则取前两位出栈进行相应计算,将结果入栈
        else
        {
            var num1 = stack.Pop();
            var num2 = stack.Pop();

            switch (c)
            {
                case '+':
                    stack.Push(num2 + num1);
                    break;
                case '-':
                    stack.Push(num2 - num1);
                    break;
                case '*':
                    stack.Push(num2 * num1);
                    break;
                case '/':
                    stack.Push(num2 / num1);
                    break;
            }
        }
    }
    return stack.Pop();
}

/// <summary>
/// 全角字符转半角
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static string ToDBC(string input)
{
    input = input.Trim();
    char[] c = input.ToCharArray();
    for (int i = 0; i < c.Length; i++)
    {
        if (c[i] == 12288)
        {
            c[i] = (char)32; continue;
        }
        if (c[i] > 65280 && c[i] < 65375)
            c[i] = (char)(c[i] - 65248);
    }
    return new string(c);
}

/// <summary>
/// 设置优先级
/// </summary>
/// <param name="symbol">运算符</param>
/// <returns></returns>
public static int SetPriority(char symbol)
{
    int level = default(int);

    switch (symbol)
    {
        case '+':
            level = 1;
            break;
        case '-':
            level = 1;
            break;
        case '*':
            level = 2;
            break;
        case '/':
            level = 2;
            break;
        case '(':
            level = 9;
            break;
        case ')':
            level = 9;
            break;
    }

    return level;
}

运行结果为:

image.png

关于这个方法还有很多不足之处,比如现在只是允许10以下的数字运算,还有优先级的判断也不完善,欢迎各位大佬指正!