Постфиксная запись к дереву выражений

Решение, которое работает в моем случае - Visual Studio 2015 Enterprise, проект .NET 4.6.1

  1. Обновление до обновления 3
  2. Установка инструментов веб-разработчика

25
задан Ikke 8 January 2009 в 11:05
поделиться

2 ответа

Создайте стек, содержащий узлы, которые могли быть частью дерева

  1. операнды Нажатия на стеке (A, 2, B, и т.д. операнды), поскольку вершины, не связанные с любым деревом в любом направлении
  2. операторы For, выталкивают необходимые операнды от стека, создают узел с оператором наверху, и операнды, зависающие ниже его, продвигают новый узел на стек

Для Ваших данных:

  1. Нажатие на стек
  2. Нажатие 2 на стек
  3. Pop 2 и A, создайте ^-node (с A и 2 ниже), продвиньте его на стеке
  4. Нажатие 2 на стеке
  5. Нажатие на стеке
  6. , Pop A и 2 и объединение для формирования *-node
  7. и т.д.
  8. и т.д.

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

55
ответ дан Guy Coder 15 October 2019 в 15:35
поделиться

Делает этот корректный взгляд:

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]
5
ответ дан Community 15 October 2019 в 15:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: