【问题标题】:Postfix notation to expression tree表达式树的后缀符号
【发布时间】:2009-01-08 11:05:46
【问题描述】:

关于如何将表达式树转换为后缀表示法的资源已经足够多,而且并不难。

但我必须将后缀表达式解析为表达式树。

表达式为:

A 2 ^ 2 A * B * - B 2 ^ + A B - /

我真的不知道如何解释这个表达式。有人知道如何处理这个吗?

【问题讨论】:

    标签: algorithm language-agnostic


    【解决方案1】:

    创建一个堆栈,其中包含可能是树的一部分的节点

    1. 将操作数推入堆栈(A、2、B 等是操作数)作为叶节点,不绑定到任何方向的任何树
    2. 对于操作符,将必要的操作数从堆栈中弹出,创建一个操作符在顶部的节点,操作数挂在其下方,将新节点压入堆栈

    对于您的数据:

    1. 将 A 压入堆栈
    2. 将 2 压入堆栈
    3. 弹出 2 和 A,创建 ^-node(下面有 A 和 2),将其压入堆栈
    4. 将 2 推入堆栈
    5. 将 A 推入堆栈
    6. 弹出 A 和 2 并组合形成 *-node

    这里有一个LINQPad 可以试验的程序:

    // Add the following two using-directives to LINQPad:
    // System.Drawing
    // System.Drawing.Imaging
    
    static Bitmap _Dummy = new Bitmap(16, 16, PixelFormat.Format24bppRgb);
    static Font _Font = new Font("Arial", 12);
    
    void Main()
    {
        var elementsAsString = "A 2 ^ 2 A * B * - B 2 ^ + A B - / 2 ^";
        var elements = elementsAsString.Split(' ');
    
        var stack = new Stack<Node>();
        foreach (var element in elements)
            if (IsOperator(element))
            {
                Node rightOperand = stack.Pop();
                Node leftOperand = stack.Pop();
                stack.Push(new Node(element, leftOperand, rightOperand));
            }
            else
                stack.Push(new Node(element));
    
        Visualize(stack.Pop());
    }
    
    void Visualize(Node node)
    {
        node.ToBitmap().Dump();
    }
    
    class Node
    {
        public Node(string value)
            : this(value, null, null)
        {
        }
    
        public Node(string value, Node left, Node right)
        {
            Value = value;
            Left = left;
            Right = right;
        }
    
        public string Value;
        public Node Left;
        public Node Right;
    
        public Bitmap ToBitmap()
        {
            Size valueSize;
            using (Graphics g = Graphics.FromImage(_Dummy))
            {
                var tempSize = g.MeasureString(Value, _Font);
                valueSize = new Size((int)tempSize.Width + 4, (int)tempSize.Height + 4);
            }
    
            Bitmap bitmap;
            Color valueColor = Color.LightPink;
            if (Left == null && Right == null)
            {
                bitmap = new Bitmap(valueSize.Width, valueSize.Height);
                valueColor = Color.LightGreen;
            }
            else
            {
                using (var leftBitmap = Left.ToBitmap())
                using (var rightBitmap = Right.ToBitmap())
                {
                    int subNodeHeight = Math.Max(leftBitmap.Height, rightBitmap.Height);
                    bitmap = new Bitmap(
                        leftBitmap.Width + rightBitmap.Width + valueSize.Width,
                        valueSize.Height + 32 + subNodeHeight);
    
                    using (var g = Graphics.FromImage(bitmap))
                    {
                        int baseY  = valueSize.Height + 32;
    
                        int leftTop = baseY; // + (subNodeHeight - leftBitmap.Height) / 2;
                        g.DrawImage(leftBitmap, 0, leftTop);
    
                        int rightTop = baseY; // + (subNodeHeight - rightBitmap.Height) / 2;
                        g.DrawImage(rightBitmap, bitmap.Width - rightBitmap.Width, rightTop);
    
                        g.DrawLine(Pens.Black, bitmap.Width / 2 - 4, valueSize.Height, leftBitmap.Width / 2, leftTop);
                        g.DrawLine(Pens.Black, bitmap.Width / 2 + 4, valueSize.Height, bitmap.Width - rightBitmap.Width / 2, rightTop);
                    }
                }
            }
    
            using (var g = Graphics.FromImage(bitmap))
            {
                float x = (bitmap.Width - valueSize.Width) / 2;
                using (var b = new SolidBrush(valueColor))
                    g.FillRectangle(b, x, 0, valueSize.Width - 1, valueSize.Height - 1);
                g.DrawRectangle(Pens.Black, x, 0, valueSize.Width - 1, valueSize.Height - 1);
                g.DrawString(Value, _Font, Brushes.Black, x + 1, 2);
            }
    
            return bitmap;
        }
    }
    
    bool IsOperator(string s)
    {
        switch (s)
        {
            case "*":
            case "/":
            case "^":
            case "+":
            case "-":
                return true;
    
            default:
                return false;
        }
    }
    

    输出:

    【讨论】:

    • 是的,这比我要发布的内容更容易理解。
    • 谢谢,但这并不完全正确。在第 3 步和第 4 步之间,您忘记将 2 压入堆栈。
    【解决方案2】:

    这看起来是否正确:

    for n in items:
        if n is argument:
            push n
        if n is operator:
            b = pop      // first pop shall yield second operand   
            a = pop      // second pop shall yield first operand
            push a+n+b
     answer = pop
    
    
    
    A 2 ^ 2 A * B * - B 2 ^ + A B - /
    

    在你的 statment 上运行它应该会产生一个像这样演变的堆栈:

    [A]
    [A, 2]
    [A^2]
    [A^2, 2]
    [A^2, 2, A]
    [A^2, 2*A]
    [A^2, 2*A, B]
    [A^2, 2*A*B]
    [A^2-2*A*B]
    [A^2-2*A*B, B]
    [A^2-2*A*B, B, 2]
    [A^2-2*A*B, B^2]
    [A^2-2*A*B+B^2]
    [A^2-2*A*B+B^2, A]
    [A^2-2*A*B+B^2, A, B]
    [A^2-2*A*B+B^2, A-B]
    [A^2-2*A*B+B^2/A-B]
    

    【讨论】:

    • 最有效。堆栈反转操作数,因此您必须将 b + n + a 放在堆栈上
    猜你喜欢
    • 2014-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-02
    • 1970-01-01
    • 2013-11-12
    • 2018-01-29
    相关资源
    最近更新 更多