无法在递归方法中设置对象

Can't set an object in a recursive method

我正在尝试向二叉搜索树添加一个节点。 这是比较两个节点的地方 - 您要添加的节点和树中的一个节点(第一次是它的根节点)。

    ...
    Compare(newNode, tree.root);
    ...

    public static void Compare(Node newN, Node comN)
        {
            if (comN == null)
            {
                comN = newN;
                return;
            }
            else
            {
                if (newN.data < comN.data)
                { Compare(newN, comN.left); }
                else if (newN.data > comN.data)
                { Compare(newN, comN.right); }
                else if (newN == comN)
                    return;
            }
        }
        // .data = int value of the node

当我通过时:

在"comN = newN;"部分,设置节点。然而,在"return;"之后它跳回了一个级别并且left/right节点(我们之前设置的节点)仍然设置为null。

有什么建议吗? (很抱歉可能使用不正确的术语,我是新手)

由于 C# 传递参数的方式,默认情况下,您使用的是本地引用。将 comN 设置为 newN 不会复制值:它将您的本地引用设置为同一对象,而不更新调用代码中的引用。您可以通过如下更改代码来获得预期的行为:

Compare(newNode, ref tree.root);
...

public static void Compare(Node newN, ref Node comN)
    {
        if (comN == null)
        {
            comN = newN;
            return;
        }
        else
        {
            if (newN.data < comN.data)
            { Compare(newN, ref comN.left); }
            else if (newN.data > comN.data)
            { Compare(newN, ref comN.right); }
            else if (newN == comN)
                return;
        }
    }

有关引用类型和参数的详细信息,请参阅 Passing Reference-Type Parameters (C# Programming Guide)

我将把它称为 class BST 而不是 Node 因为它使正在发生的事情更清楚一些。假设它被定义为接受一个 data 和一个左右节点作为参数:

// C# 6 for brevity
class BST
{
    public int Data { get; }
    public BST Left { get; }
    public BST Right { get; }

    public Bst(int data, BST left, BST right) 
    {
        Data = data;
        Left = left;
        Right = right;
    }
}

您的插入算法可以定义如下:

static class BSTExtensions
{
    public static BST Insert(this BST bst, BST n)
    {
        if (bst == null)
            return n;

        if (n.Data < bst.Data)
            return new BST(bst.Data, bst.Left.Insert(n), bst.Right);
        if (n.Data > bst.Data)
            return new BST(bst.Data, bst.Left, bst.Right.Insert(n));

        return bst;
    }
}

很容易理解这里发生的事情。

  1. 如果您应该比较的节点不存在,那么这就是新节点应该占据的位置。
  2. 如果新结点的值小于当前结点的值,则插入左子树。
  3. 如果新节点的值大于当前节点的值,则插入右子树。
  4. 如果值相等(唯一剩余的可能性),则不需要更改。只是 return 原始树。

虽然我也让这个例子中的树不可变,但如果你在你的 class 中实现 setter,你可以更有效地做到这一点,同时仍然不需要 ref.