码迷,mamicode.com
首页 > 其他好文 > 详细

逆波兰式篇(后缀表达式)

时间:2014-12-06 12:45:15      阅读:277      评论:0      收藏:0      [点我收藏+]

标签:blog   http   io   ar   os   使用   sp   for   strong   

一、逆波兰表示法Reverse Polish notationRPN,或逆波兰记法),是一种数学表达式方式,在逆波兰记法中,所有操作符置于操作数的后面。也称为后缀表达式。

二、一般算法

将一个普通的中序表达式转换为逆波兰表达式的一般算法是:

  1.  首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。
  2.  读入一个中缀表达式,为了方便起见,可在其最右端追加一个最低优先级运算符(如:#号)。(这样做的目的是,最后读入#号运算符时将运算符栈中所有运算符都输        出)。
  3.  从左至右扫描该中缀表达式,如果当前字符是数字,则分析到该数字串的结束,并将该数字串直接输出。
  4.  如果不是数字,该字符则是运算符,此时需比较该运算符与运算符栈顶运算符的优先关系:
  5.   (1)、若该运算符优先级高于栈顶运算符优先级别(或栈为空),则直接将该运算符压入运算符栈中;
  6.   (2)、若该运算符优先级小于或等于此运算符栈顶的运算符,则弹出栈顶运算符并输出,重复比较、输出,直到栈为空或该运算符优先级高于栈顶运算符,然后将该运算  符入栈。
  7.  重复上述操作(3)-(4)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,输出结果便是中缀表达式转化为逆波兰表示的简单算术表达式。

三、举例说明

  例如中缀表达式:9+(3-1) X 3+10+2,其实是我们人类所理解的四则表达运算式,现在我们将其转为机器方便识别的后缀表达式。

四、算法实现

namespace Eduii.Practice.StackDemo
{
    /*
     * 词汇:
     *  postfix expression 后缀表达式
     *  infix expression   中缀表达式
     *  prefix expression  前缀表达式 
     * 
     */

    /*
     *分析:
     *目前四则运算符包括:(、)、+、-、*、/、%
     * 优先级:
     *      1、* 、/、%
     *      2、+ 、-
     *      3、(
     *      4、)
     * 
     */

    /*
     *拓展: 
     *    1、字符串包含其他字符的判断
     *    2、四则运算非个位时
     *    3、包含小数点
     *    4、包含正负号
     *    5、......
     */

    /*
     *参考文档
     *  http://www.cnblogs.com/mygmh/archive/2012/10/06/2713362.html
     *  http://www.nowamagic.net/librarys/veda/detail/2307
     *  http://www.cnblogs.com/stay-foolish/archive/2012/04/25/2470590.html
     */

    /// <summary>
    /// 逆波兰式的算法实现
    /// </summary>
    public class RPExpression
    {
        /// <summary>
        ///  使用字符串存储
        /// </summary>
        /// <param name="infixExpression"></param>
        /// <returns></returns>
        /*
         *从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后
         *缀表达式的一部分;若是符号,若为‘(’,直接压入操作栈,
         *若为其他字符则判断其与栈顶符号的优先级,是右括号或优先级低
         *于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出, 并将当前符号进栈,一直
         *到最终输出后缀表达式为止。 
         * 
         */
        public string Convert2PostfixExpWithString(string infixExpression)
        {
            //后缀表达式
            string postfixExp = string.Empty;
            //先处理空格
            if (string.IsNullOrWhiteSpace(infixExpression))
                return postfixExp;
            //去除空格
            infixExpression = infixExpression.Trim();
            //操作栈
            Stack<char> operatorStack = new Stack<char>();
            //四则表达式长度
            int length = infixExpression.Length;
            //临时存储字符
            char temp;
            //数字
            string digital = string.Empty;
            for (int i = 0; i < length; i++)
            {
                temp = infixExpression[i];
                bool isOperator = IsOperator(temp);
                if (isOperator)
                {
                    if (!string.IsNullOrWhiteSpace(digital))
                    {
                        postfixExp += string.Format("{0},", digital);
                        digital = string.Empty;
                    }
                    if (temp == ‘(‘)
                        operatorStack.Push(temp);
                    //判断是否为‘(‘
                    else if (temp == ‘)‘)
                    {
                        //当为‘)’时,直接取出栈顶的元素,直到第一个‘(‘为止
                        char topElement = operatorStack.Pop();  //返回栈顶元素当不将其移除
                        while (topElement != ‘(‘)
                        {
                            postfixExp += string.Format("{0},", topElement);
                            if (operatorStack.Count == 0)
                                break;
                            topElement = operatorStack.Pop();
                        }
                    }
                    else
                    {
                        //栈为空时直接插入当前运算符
                        if (operatorStack.Count == 0)
                            operatorStack.Push(temp);
                        //栈中存在操作符时要判断优先级
                        else
                        {
                            char topElement = operatorStack.Peek();
                            while (topElement != ‘#‘)
                            {
                                if (ComparePriority(temp, topElement) > 0)
                                {
                                    operatorStack.Push(temp);
                                    topElement = ‘#‘;
                                }
                                else
                                {
                                    //当前栈顶出栈
                                    postfixExp += string.Format("{0},", topElement);
                                    operatorStack.Pop();
                                    if (operatorStack.Count != 0)
                                        topElement = operatorStack.Peek();
                                    else
                                    {
                                        operatorStack.Push(temp);
                                        topElement = ‘#‘;
                                    }
                                }
                            }
                        }
                    }
                }
                else
                {
                    //数字拼接
                    digital += temp;
                    //直接输出数字
                    if (i == length - 1)
                    {
                        postfixExp += string.Format("{0},", digital);
                    }
                }
            }

            //输出所有的操作
            while (operatorStack.Count > 0)
            {
                postfixExp += string.Format("{0},", operatorStack.Pop());
            }
            return postfixExp;
        }



        //比较优先级
        private int ComparePriority(char ch1, char ch2)
        {
            int ch1Pri = GetPriority(ch1);
            int ch2Pri = GetPriority(ch2);
            return ch1Pri - ch2Pri;
        }

        //获得字符优先级
        private int GetPriority(char ch)
        {
            switch (ch)
            {
                case ‘(‘:
                    return -1;
                case ‘+‘:
                case ‘-‘:
                    return 0;
                case ‘*‘:
                case ‘/‘:
                case ‘%‘:
                    return 1;
                default:
                    throw new Exception("未定义操作符.");
            }
        }

        // 判断字符是否为操作符
        private bool IsOperator(char ch)
        {
            if (ch == ‘+‘ || ch == ‘-‘ || ch == ‘*‘ || ch == ‘/‘ || ch == ‘%‘ || ch == ‘(‘ || ch == ‘)‘)
                return true;
            return false;
        }

        /// <summary>
        /// 计算后缀表达式值
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        /*
         *从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符
         *号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈, 一直到最终获得结果。 
         */
        public decimal CalculatePostfixExp(string expression)
        {
            if (string.IsNullOrWhiteSpace(expression))
                return 0;
            //清除空格
            expression = expression.Trim();
            //数据
            decimal digigtal = 0;
            //取得后缀表达式中的字符
            int i = 0;
            char topElement = expression[i];
            Stack<decimal> dataStack = new Stack<decimal>();
            while (topElement != ‘#‘)
            {
                if (topElement != ‘,‘)
                {
                    if (IsOperator(topElement))
                    {
                        //取出栈顶元素进行运算
                        decimal num1 = dataStack.Pop();
                        decimal num2 = dataStack.Pop();
                        decimal result = Calculate(num2, num1, topElement);
                        dataStack.Push(result);

                    }
                    else
                    {
                        int singleDigit = topElement - 48;
                        if (digigtal != 0)
                            digigtal = digigtal * 10 + singleDigit;
                        else
                            digigtal = singleDigit;
                    }
                }
                else
                {
                    if (digigtal != 0)
                    {
                        dataStack.Push(digigtal);
                        digigtal = 0;
                    }
                }
                if (i == expression.Length - 1)
                    break;
                i++;
                topElement = expression[i];
            }
            return dataStack.Pop();
        }

        //两数相加
        private decimal Calculate(decimal num1, decimal num2, char ope)
        {
            switch (ope)
            {
                case ‘+‘:
                    return num1 + num2;
                case ‘-‘:
                    return num1 - num2;
                case ‘*‘:
                    return num1 * num2;
                case ‘/‘:
                    return num1 / num2;
                default:
                    throw new ApplicationException("未定义的数据类型.");
            }
        }
    }
}

  

逆波兰式篇(后缀表达式)

标签:blog   http   io   ar   os   使用   sp   for   strong   

原文地址:http://www.cnblogs.com/xiuyuanjing/p/4138916.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!