在二叉搜索树中添加节点

时间:2014-08-12 07:51:51

标签: c# binary-search-tree

注意:这是我只需要指导的家庭作业。我当时没有要求任何其他帮助。

我已经查找了如何在C#中添加二进制搜索树中的节点,但是我得到了非常不同类型的答案。所以,假设我有节点类:

class Node
{
    public int value;
    public Node left;
    public Node right;

    public Node(int v)
    {
        value = v;
        left = right = null;
    }
}

我的添加功能所在的类:

class BST
{
    public void addNode(int x, Node root)
    {
        Node newNode = new Node(x);

        if (root == null)
        {
            root = newNode;
        }
        if (root.value == newNode.value)
        {
            return;
        }
        else if (newNode.value < root.value)
        {
            if (root.left == null)
            {
                root.left = newNode;
            }
            else
            {
                addNode(x, root.left);
            }
        }
        else if (newNode.value > root.value)
        {
            if (root.right == null)
            {
                root.right = newNode;
            }
            else
            {
                addNode(x, root.right);
            }
        }
    }
}

所以现在我的问题是:我很确定我已经掌握了大部分逻辑,但是我怀疑的是,当我递归调用函数时,我不确定树是否实际上转到了左子树递归调用。或者我做得对吗?

2 个答案:

答案 0 :(得分:3)

如果您认为自己做得对,那么您应该对其进行测试。首先,您应该增强类,以便在调试器中更容易可视化。显而易见的事情是向Node添加“ToString()”方法:

public class Node
{
    public int value;
    public Node left;
    public Node right;

    public Node(int v)
    {
        value = v;
        left = right = null;
    }

    public override string ToString()
    {
        return value.ToString();
    }
}

现在,只需将鼠标悬停在类实例上,即可在Visual Studio中检查树的值。根据Sayse的建议,在开始构建树之后在代码中设置断点:

enter image description here

将鼠标悬停在根节点上。一个面板将出现“ToString()”值 - 节点值,实际上,由于你的“ToString()”覆盖。您还会看到一个“+”按钮。如果单击该按钮,Visual Studio将显示类实例的字段和属性,您可以递归地展开它们:

enter image description here

检查了调试器中的值后,您现在可能需要更复杂的方法从类中提取数据,例如返回列表中Node内或下的所有值:

public class Node
{
    public IList<int> ToList()
    {
        var list = new List<int>();
        AddToList(list);
        return list;
    }

    public void AddToList(List<int> list)
    {
        if (left != null)
            left.AddToList(list);
        list.Add(value);
        if (right != null)
            right.AddToList(list);
    }
}

这应该可以让你看到你拥有的东西,并验证它是你所期望的。您可以使用Enumerable.SequentialEqual在代码中添加asserts,以确保返回的列表正确无误,如下所示:

    private static void TestBST()
    {
        var bst = new BST();
        Node root = new Node(23);
        bst.addNode(13, root);
        bst.addNode(-12, root);
        bst.addNode(1, root);
        Debug.Assert(Enumerable.SequenceEqual(root.ToList(), new int[] { -12, 1, 13, 23 }));
    }

您还可以从Immediate Window调用“ToList()”方法,这样您可以在程序在断点处停止时键入c#表达式并对其进行解释并以交互方式显示结果:

enter image description here

因此,总而言之,无论何时设计新类,总是要添加逻辑,以便于可视化,调试和断言代码的正确性。 TobiMcNamobi提到的单元测试方法是正式的方法,但您可以在家庭作业代码中非正式地进行。

(顺便说一下,你注意到我在上面明确地分配了一个根节点,而不是使用BST类实例来创建根节点?你剩下的作业就是找出原因。)

答案 1 :(得分:0)

你的左/右逻辑在大多数情况下是可以的,但开始是令人困惑的:

if (root == null)
{
   root = newNode;
}
if (root.Value == newNode.Value) 
{
    return;
} 

实际上很多。如果rootnull,则表示出现问题。 你可以忽略这一点:

if (root == null) 
    return;    

if (newNode.Value < root.Value)

或者让用户现在,那是错误的

if (root == null) 
    throw new ArgumentNullException("root");

但是,如果您希望在root来电之外更改AddNode,则必须将root作为reference传递:

 public void AddNode(int x, ref Node root) 
 {
     Node newNode = new Node(x);
     this->AddNode(newNode, ref root);
 }

 private void AddNode(Node newNode, ref Node root)
 {
      if (root == null) 
      {
           root = newNode;
           return;
      }
      if (root.Value == newNode.Value) 
      {
           return;
      } 

要改进的一些事项:

最好在UpperCamelCase中用C#编写方法名称,这样就可以调用方法AddNode。这不会改变逻辑,但每种编程语言都有自己的风格指南,应该尝试遵循。 对于公共属性/字段也是如此,因此请将其称为LeftRightValue

每次拨打AddNode时,您都会创建一个新的Node对象来保存x。 这是可以避免的开销。只需创建另一个funcktion AddNode,它接收一个Node作为第一个参数,并从你的函数中调用该函数:

public void AddNode(int x, Node root) 
{
    Node newNode = new Node(x);
    this->AddNode(newNode, root);
}

private void AddNode(Node newNode, Node root)
{
    if (root == null) 
    {
        root = newNode;
    }
    if (root.Value == newNode.Value) 
    {
        return;
    } 
    else if (newNode.Value < root.Value) 
    {
        if (root.Left == null) 
        {
            root.Left = newNode;
        } 
        else 
        {
            AddNode(newNode, root.Left);
        }
    } 
    else if (newNode.Value > root.Value) 
    {
        if (root.Right == null) 
        {
            root.Right = newNode;
        } 
        else 
        {
            AddNode(newNode, root.Right);
        }
    }
}