代码之家  ›  专栏  ›  技术社区  ›  Ikke

表达式树的后缀表示法

  •  25
  • Ikke  · 技术社区  · 17 年前

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

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

    2 回复  |  直到 17 年前
        1
  •  58
  •   Guy Coder    12 年前

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

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

    1. 将一个容器推到堆栈上
    2. 将2推到堆栈上
    3. 弹出2和A,创建^-节点(下面有A和2),将其推到堆栈上
    4. 将2推到堆栈上
    5. 在堆栈上推
    6. 弹出A和2并组合成*-节点

    tree structure

    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;
        }
    }
    

    LINQPad output

        2
  •  5
  •   Community Mohan Dere    12 年前

    这看起来正确吗:

    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 - /
    

    [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]
    
    推荐文章