下午所有,
我在C#中实现了一个简单的二叉树,我打算用它来递归地创建数学表达式树。但是我遇到了问题,因为多年以来我不得不做递归调用我正在努力让我听到为什么以下只适用于深度为2的二叉树而不是更深的树。
当然,如果递归是正确的,它应该能够构造树到深度n。这是代码:
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;
}
上述函数采用形成前缀数学表达式的字符列表(例如* + 3 4 - 5 6
)。令人讨厌的是,我使用以下代码递归地创建了前缀表达式:
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;
}
我尝试以与生成字符串相同的方式创建树,但无法以任何常识方式使其工作。我正在使用binary tree class found on MSDN的略微修改版本。我修改它有一个自动添加到左或右子树的添加功能,所以我不必像这个例子那样指定Root.Left.Left.Left等来创建树。
如果任何正文可以帮我纠正我的递归树创建代码,以便它适用于n深度的树,我会非常感激。我对C#比较新,所以如果上面的任何内容略显粗略,我会道歉。
答案 0 :(得分:2)
在进行这样的递归调用时,你不应该依赖于全局变量(通常,变量的范围应该尽可能地窄,f
和t
似乎没有任何理由。 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;
}
是类级变量)。你的代码对我来说没有多大意义,但我想主要问题是你将每个节点直接添加到根目录。我会这样做:
maxDepth
我认为没有太多理由让NumberNode
存在,但如果你真的想要它,那么实施它应该是微不足道的。
此外,拥有节点的继承层次结构(如OperatorNode
,IEnumerator<T>
)可能是有意义的,但这取决于您想要用它们做什么。
编辑:@Eric,不多。我可以使用Queue<T>
而不是isOperator()
(现在我认为它可能是一个更好的选择)。而且我必须将结果的创建推迟到最后,wchich也意味着我必须修改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);
}
。
{{1}}