简体   繁体   English

递归创建数学表达式二叉树

[英]Recursively creating a mathematical expression binary tree

Afternoon all, 下午所有,

I have implemented a simple binary tree in C#, I intend on using it to create mathematical expression trees recursively. 我在C#中实现了一个简单的二叉树,我打算用它来递归地创建数学表达式树。 But I am running into problems, as it has been years since I have had to do recursive calls I am struggling to get my heard around why the following only works for binary trees of depth 2 and not trees of any greater depth. 但是我遇到了问题,因为多年以来我不得不做递归调用我正在努力让我听到为什么以下只适用于深度为2的二叉树而不是更深的树。

Surely if the recursion was correct it should be able to construct trees to depth n. 当然,如果递归是正确的,它应该能够构建深度为n的树。 Here is the code : 这是代码:

Node<T> f;
Node<T> t;
Node<T> subRoot;
Node<T> root;

////Only works with trees of depth 2.

private Node<T> Tree(List<T> prefixBank, int maxDepth)
{
    if (prefixBank.Count != 0)
    {
        if (maxDepth == 0)
        {
            t = new Node<T>(prefixBank[0]);
            subRoot.Add(t);

            prefixBank.Remove(prefixBank[0]);
        }
        else
        {
            if (root == null)
            {
                root = new Node<T>(prefixBank[0]);
                prefixBank.Remove(prefixBank[0]);
                Tree(prefixBank, maxDepth - 1);
            }

            f = new Node<T>(prefixBank[0]);

            if (isOperator(f))
            {
                root.Add(f);
                prefixBank.Remove(prefixBank[0]);
                subRoot = f;
            }

            for (int i = 0; i < 2; i++)
            {
                Tree(prefixBank, maxDepth - 1);
            }
        }
    }
return f;
}

The above function takes a list of characters that form a prefix mathematical expression (for example * + 3 4 - 5 6 ). 上面的函数采用形成前缀数学表达式的字符列表(例如* + 3 4 - 5 6 )。 Annoyingly I create the prefix expression recursively using this code: 令人讨厌的是,我使用以下代码递归地创建了前缀表达式:

string prefixExpression = String.Empty;

private string generateExpression(Random rand, GenerationMethod generationMethod, int maxDepth)
{
    if ((maxDepth == 0) || ((generationMethod == GenerationMethod.Grow) && (rand.NextDouble() < randomRate)))
    {
        operand.GenerateValue(Type.Terminal, rand);
        prefixExpression += " " + operand.Value;
    }
    else
    {
        operator.GenerateValue(Type.Function, rand);
        prefixExpression += " " + operator.GeneValue;

        //2 is the arity of the function right an arity checker function so that unary operators can be utilised
        for (int i = 0; i < 2; i++)
        {
            generateExpression(rand, generationMethod, maxDepth - 1);
        };
    }
    return prefixExpression;
}

I have tried to create a tree in the same way I have generated the string but cannot get it to work in any common sense way. 我尝试以与生成字符串相同的方式创建树,但无法以任何常识方式使其工作。 I am using a slightly modified version of the binary tree class found on MSDN . 我正在使用MSDN上的二进制树类的略微修改版本。 I modified it to have an add function that automatically added to either the left or right subtree so I dont have to specify Root.Left.Left.Left etc like this example does to create the tree. 我修改它有一个自动添加到左或右子树的添加功能,所以我不必像这个例子那样指定Root.Left.Left.Left等来创建树。

If any body could help me correct my recursive tree creation code so that it works for trees of n depth I would really appreciate it. 如果任何正文可以帮助我纠正我的递归树创建代码,以便它适用于n深度的树我真的很感激它。 Im relatively new to C# so I apologise if anything above is slightly sketchy. 我对C#比较新,所以如果上面的任何内容略显粗略,我会道歉。

You shoudn't rely on global variables when making recursive calls like this (and in general, the scope of your variables should be as narrow as possible, there doesn't seem to be any reason for f and t to be class-level variables). 在进行这样的递归调用时,你不应该依赖于全局变量(通常,变量的范围应该尽可能地窄, ft似乎没有任何理由成为类级变量)。 Your code doesn't make much sense to me, but I guess the main probelm is that you are adding every node directly to the root. 你的代码对我来说没有多大意义,但我想主要问题是你将每个节点直接添加到根目录。 I would do it like this: 我会这样做:

public Node<T> Tree(Queue<T> prefixBank)
{
    var node = new Node<T>(prefixBank.Dequeue());

    if (isOperator(node))
    {
        for (int i = 0; i < 2; i++)
        {
            node.Add(Tree(prefixBank));
        }
    }

    return node;
}

I don't see much reason to have maxDepth there, but if you really want it, it should be trivial to implement. 我没有太多理由在那里拥有maxDepth ,但如果你真的想要它,那么实现它应该是微不足道的。

Also, it might make sense to have a inheritance hierarchy of nodes (like NumberNode , OperatorNode ), but that depends on what exactly do you want to do with them. 此外,拥有节点的继承层次结构(如NumberNodeOperatorNode )可能是有意义的,但这取决于您想要对它们做什么。

EDIT : @Eric, not much. 编辑 :@Eric,不多。 I can use IEnumerator<T> instead of Queue<T> (which, now that I think about it, is probably a better choice anyway). 我可以使用IEnumerator<T>代替Queue<T> (现在我想起来,无论如何都可能是一个更好的选择)。 And I have to pospone the creation of the result until the end, wchich also means I have to modify isOperator() to work on T and not Node<T> . 而且我必须将结果的创建推迟到最后,wchich也意味着我必须修改isOperator()来处理T而不是Node<T>

public Node<T> Tree(IEnumerable<T> prefixBank)
{
    return Tree(prefixBank.GetEnumerator());
}

public Node<T> Tree(IEnumerator<T> enumerator)
{
    enumerator.MoveNext();
    var value = enumerator.Current;

    var children = new List<Node<T>>(2);

    if (isOperator(value))
    {
        for (int i = 0; i < 2; i++)
        {
            children.Add(Tree(enumerator));
        }
    }

    return new Node<T>(value, children);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM