我有一个用c#编写的二叉树,其节点用IComparable数据定义。这一切都很好,因为我可以使用我喜欢的任何数据类型填充树(尽管我一次只尝试使用单一类型的数据填充它)并执行查找深度,按顺序等功能搜索,计数叶子等
我正在尝试编写一个函数,使用递归算法在树中查找数据值。算法查找数据,但在找到数据时不会停止。有一个例外 - 当数据在根节点中时。我无法弄清楚它出了什么问题。该函数报告它找到了数据,此时它应该返回该节点并退出,但它会继续查看子节点。
感谢接受的答案,这是我的工作代码:
private TreeNode findValueStartingAtNode(TreeNode node, IComparable value)
{
if (node == null)
{
return null;
}
int test = value.CompareTo(node.data);
if (test < 0)
{
return findValueStartingAtNode(node.left_child, value);
}
else if (test > 0)
{
return findValueStartingAtNode(node.right_child, value);
}
else
{
return node;
}
}
代码:
public TreeNode findValue(IComparable value)
{
TreeNode node = findValueStartingAtNode(this.root, value);
if (node == null)
{
Console.WriteLine("value not found");
return null;
}
else
{
return findValueStartingAtNode(this.root, value);
}
}
private TreeNode findValueStartingAtNode(TreeNode node, IComparable value)
{
Console.WriteLine("looking for value {0}", value);
if (node == null)
{
Console.WriteLine("node is null -- returning null");
return null;
}
else if (value.CompareTo(node.data) == 0)
{
Console.WriteLine("value found at current node");
Console.WriteLine("current node data is {0}", node.data);
Console.WriteLine("done and returning node");
return node;
}
else
{
Console.WriteLine("checking children");
TreeNode left = findValueStartingAtNode(node.left_child, value);
TreeNode right = findValueStartingAtNode(node.right_child, value);
Console.WriteLine("the values are left: {0}, right: {1}", left.data, right.data);
if (value.CompareTo(left.data) == 0)
{
Console.WriteLine("value found in left child");
return left;
}
else if (value.CompareTo(right.data) == 0)
{
Console.WriteLine("value found in right child");
return right;
}
else
{
Console.WriteLine("value not found in either child");
Console.WriteLine("current node data is {0}", node.data);
return null;
}
}
}
输出:
C:\Users\abalter\Documents\CS273\TreeNode\TreeNode\bin\Debug>TreeNode.exe
looking for value 50
value found at current node
current node data is 50
done and returning node
looking for value 50
value found at current node
current node data is 50
done and returning node
(in main) value 50 found
looking for value 45
checking children
looking for value 45
value found at current node
current node data is 45
done and returning node
looking for value 45
checking children
looking for value 45
checking children
looking for value 45
node is null -- returning null
looking for value 45
checking children
looking for value 45
node is null -- returning null
looking for value 45
node is null -- returning null
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
at TreeNode.BinaryTree.findValueStartingAtNode(TreeNode node, IComparable value) in c:\Users\abalter\Documents\CS273\TreeNode\TreeNode\BinaryTree.cs:line 220
at TreeNode.BinaryTree.findValueStartingAtNode(TreeNode node, IComparable value) in c:\Users\abalter\Documents\CS273\TreeNode\TreeNode\BinaryTree.cs:line 218
at TreeNode.BinaryTree.findValueStartingAtNode(TreeNode node, IComparable value) in c:\Users\abalter\Documents\CS273\TreeNode\TreeNode\BinaryTree.cs:line 217
at TreeNode.BinaryTree.findValueStartingAtNode(TreeNode node, IComparable value) in c:\Users\abalter\Documents\CS273\TreeNode\TreeNode\BinaryTree.cs:line 218
at TreeNode.BinaryTree.findValue(IComparable value) in c:\Users\abalter\Documents\CS273\TreeNode\TreeNode\BinaryTree.cs:line 186
at TreeNode.Program.Main(String[] args) in c:\Users\abalter\Documents\CS273\TreeNode\TreeNode\Program.cs:line 36
C:\Users\abalter\Documents\CS273\TreeNode\TreeNode\bin\Debug>
答案 0 :(得分:4)
二进制搜索树具有某些属性。这里重要的属性是,对于每个节点,该节点的左子树中的所有内容都小于节点的值,并且右子树中的所有内容都较大(根据比较器)。
你只需要查看一个子树。使用该属性查找您要查找的项目:
private TreeNode findValueStartingAtNode(TreeNode node, IComparable value)
{
if (node == null) return null;
int comp = value.CompareTo(node.data);
if (comp == 0) return node; //Found it
if (comp < 0) return findValueStartingAtNode(node.left_child, value); //The item must be in the left subtree
return findValueStartingAtNode(node.right_child, value); // The item must be in the right subtree
}
Bonus:而不是递归方法,这是我自己的实现中的迭代搜索函数:(它也是通用的)
private BinaryTreeNode<T> Search(BinaryTreeNode<T> node, T item)
{
if (node == null) return null;
int c;
while (node != null && (c = comparer.Compare(item, node.Value)) != 0)
node = c < 0 ? node.Left : node.Right;
return node;
}
答案 1 :(得分:1)
不要向左和向下看,而是检查是否找到了它,你应该只向左看。如果在那里找到它,请返回,否则向右看。如果它在那里,返回,否则返回null。您的else
看起来像这样:
Console.WriteLine("checking children");
TreeNode left = findValueStartingAtNode(node.left_child, value);
if (left != null && value.CompareTo(left.data) == 0)
{
Console.WriteLine("value found in left child");
return left;
}
else
{
TreeNode right = findValueStartingAtNode(node.right_child, value);
if (right != null && value.CompareTo(right.data) == 0)
{
Console.WriteLine("value found in right child");
return right;
}
else
{
Console.WriteLine("value not found in either child");
Console.WriteLine("current node data is {0}", node.data);
return null;
}
}
答案 2 :(得分:1)
findValueStartingAtNode
应返回null
,如果找到该值,则返回正确的TreeNode
。没有理由比较右子节点和左子节点的值,因为子节点上的递归调用将自己检查子节点的值。每当遇到没有两个子节点的节点时,它也会失败并抛出NullReferenceException。最后,您的findValue
来电正在搜索树两次。
我会用这个替换你的代码:
public TreeNode findValue(IComparable value)
{
TreeNode node = findValueStartingAtNode(this.root, value);
if (node == null)
{
Console.WriteLine("value not found");
}
return node;
}
private TreeNode findValueStartingAtNode(TreeNode node, IComparable value)
{
Console.WriteLine("looking for value {0}", value);
if (node == null)
{
Console.WriteLine("node is null -- returning null");
return null;
}
else if (value.CompareTo(node.data) == 0)
{
Console.WriteLine("value found at current node");
Console.WriteLine("current node data is {0}", node.data);
Console.WriteLine("done and returning node");
return node;
}
else
{
Console.WriteLine("checking left child");
TreeNode left = findValueStartingAtNode(node.left_child, value);
if(left != null) return left;
Console.WriteLine("checking right child");
TreeNode right = findValueStartingAtNode(node.right_child, value);
if(right != null) return right;
Console.WriteLine("value not found in either child");
Console.WriteLine("current node data is {0}", node.data);
return null;
}
}
还应该提到的是,它不具备二元搜索树的资格。它将执行深度优先搜索,仅在找到值或访问整个树时结束。
答案 3 :(得分:0)
这似乎......对我来说很复杂,双重调用和所有。
值得注意的是,树的每个节点本身都是一棵树。树的根节点和树的任何其他节点之间没有区别。你只需要做一次步行。像许多递归问题一样,树行走有两种情况:
null
)。因此,树行走逻辑是这样的:
特殊情况。如果根(当前)节点为空,则搜索失败。返回null。
一般情况。将根(当前)节点的有效负载与期望值进行比较。
这就是它的全部内容。给定这样的节点结构:
public class TreeNode<T> where T:IComparable
{
public TreeNode<T> Left { get ; set ; }
public TreeNode<T> Right { get ; set ; }
public T Payload { get ; set ; }
}
树搜索代码不应该比这个
困难得多public TreeNode<T> FindNodeWithValue( IComparable value )
{
Func<IComparable,int> compareToDesiredValue = (x) => x.CompareTo(value) ;
TreeNode<T> node = FindNodeWithValue( this.Root , compareToDesiredValue ) ;
return node ;
}
private TreeNode<T> FindNodeWithValue( TreeNode<T> root , Func<IComparable,int> compareToDesiredValue )
{
TreeNode<T> result = null ;
if ( root != null )
{
int cc = compareToDesiredValue( root.Payload ) ;
switch ( cc )
{
case 0 : result = root ; break ;
case -1 : result = FindNodeWithValue( root.Left , compareToDesiredValue ) ; break ;
case +1 : result = FindNodeWithValue( root.Right , compareToDesiredValue ) ; break ;
default : throw new InvalidOperationException() ;
}
}
return result ;
}
此外,鉴于此搜索定向,因此您无需跟踪父节点,也无需回溯替代方案,代码可以轻松实现迭代,就像这样简单:
public TreeNode<T> FindNodeWithValue( IComparable value )
{
TreeNode<T> current = this.Root ;
int cc ;
while ( current != null && 0 != (cc=current.Payload.CompareTo(value)) )
{
// if we land here, current node does not have our desired value.
// follow the appropriate left or right child.
current = cc < 0 ? current.Left : current.Right ;
}
// once the while loop completes, current holds the result, with
// null indicating failure and non-null being the subtree containing
// the desired value as its root.
return current ;
}