java - 将表示数学表达式的树转换为没有多余括号的字符串

标签 java c# .net algorithm visitor-pattern

我想将表示数学表达式转换为实际的数学表达式(像“a+b/c”这样的字符串)

树表示是您能想象到的最简单的表示:

A+B/C 就是这棵树:

OperationNode(+, A, OperationNode(/, B, C))

(A+B)/C 就是这棵树:

OperationNode(/, OperationNode(+, A, B), C)

为了将树转换为字符串,我使用了访问者模式。问题出在括号上。

我当前的访问者实现总是向节点添加括号,因此我生成的每棵树都会变成这样的字符串:

(((A+B)+C)+D)

注意多余的括号。

所以问题是:如何让我的访问者生成没有多余括号的字符串?

最佳答案

正如 NelFeal 在遍历树时所写的那样,您只需要检查子操作的优先级是否小于当前操作的优先级。

我为您实现了访客模式,希望对您有所帮助。

enum Operation
{
    Add,
    Multiply,
    Power,
    UnaryMinus,
    None,
}

static class OperationExtensions
{
    public static string ToFriendlyString(this Operation me)
    {
        switch (me)
        {
            case Operation.None:
                return "";
            case Operation.Add:
                return "+";
            case Operation.Multiply:
                return "*";
            case Operation.Power:
                return "^";
            case Operation.UnaryMinus:
                return "-";
            default:
                throw new ArgumentException();
        }
    }
}

class OperationNode
{
    public Operation Op;
    public OperationNode(Operation op)
    {
        Op = op;
    }
}

interface IVisitor
{
    void Visit(OperationNodeLeaf node);
    void Visit(OperationNode1 node);
    void Visit(OperationNode2 node);
}

sealed class Visitor : IVisitor
{
    public string Text { get; set; }

    private void Enclose(OperationNode subNode, Operation op)
    {
        if (subNode.Op < op)
        {
            Text = Text + "(";
            Visit((dynamic)subNode);
            Text = Text + ")";
        }
        else
        {
            Visit((dynamic)subNode);
        }
    }

    public void Visit(OperationNodeLeaf node)
    {
        Text = Text + node.Op.ToFriendlyString();
        Text = Text + node.Value.ToString();
    }

    public void Visit(OperationNode1 node)
    {
        Text = Text + node.Op.ToFriendlyString();
        Enclose(node.SubNode, node.Op);
    }

    public void Visit(OperationNode2 node)
    {
        Enclose(node.LeftSubNode, node.Op);
        Text = Text + node.Op.ToFriendlyString();
        Enclose(node.RightSubNode, node.Op);
    }
}

class OperationNodeLeaf : OperationNode
{
    public int Value;
    public OperationNodeLeaf(int v, Operation op = Operation.None) : base(op)
    {
        Value = v;
    }
    void Accept(IVisitor v)
    {
        v.Visit(this);
    }
}

class OperationNode1 : OperationNode
{
    public OperationNode SubNode;
    public OperationNode1(OperationNode sn, Operation op) : base(op)
    {
        SubNode = sn;
    }
    void Accept(IVisitor v)
    {
        v.Visit(this);
    }
}

class OperationNode2 : OperationNode
{
    public OperationNode LeftSubNode;
    public OperationNode RightSubNode;
    public OperationNode2(OperationNode lsn, OperationNode rsn, Operation op) : base(op)
    {
        LeftSubNode = lsn;
        RightSubNode = rsn;
    }
    void Accept(IVisitor v)
    {
        v.Visit(this);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var tree = 
            new OperationNode2(
                new OperationNode2(
                    new OperationNode2(new OperationNodeLeaf(5), new OperationNodeLeaf(6), Operation.Add),
                    new OperationNode2(new OperationNodeLeaf(5), new OperationNodeLeaf(6), Operation.Multiply),
                    Operation.Power
                    ),
                new OperationNode2(
                    new OperationNode2(new OperationNodeLeaf(1), new OperationNodeLeaf(2), Operation.Multiply),
                    new OperationNode1(new OperationNodeLeaf(7, Operation.None), Operation.UnaryMinus),
                    Operation.Add
                    ),
                Operation.Multiply
                );
        var visitor = new Visitor();
        visitor.Visit(tree);
        System.Diagnostics.Debug.WriteLine(visitor.Text);
    }
}

(5+6)^(5*6)*(1*2+-7)

关于java - 将表示数学表达式的树转换为没有多余括号的字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53467194/

相关文章:

java - JBoss ESB Action 有生命周期吗?

c# - DotNetOpenAuth - 如何使其在负载均衡器后面工作?

c# - 日志文件似乎被另一个进程锁定

c# - 双击后禁用展开

c# - 机器的 .net 核心 cpu 使用率

java - 将对象添加到 ListView - ANDROID

java - 检测代词及其名词?

c# - 使用 DateTime.ToString ("tt"时,Windows 10 中的时间输出(AM/PM)发生了变化)

c# - MS在c#/.net中将MDB Access 到Sqlite

java - 阻止 JTextArea 扩展