0

Consider I have object A which is holding reference to B object type, but this time initilized to null.

A->B( == null)

I want to replace the null with object of type B which hold reference to type C.
(B->C).
So I will get A->B->C .

Why isn't it possible to link them by giving the reference of B object(which holds null but probably linked to specific memory address behind the scenes and assign to it the C object instead of null so afterward it will be A->B->C?

Why I must forward the A object for being able to do this manipulation?

This question is asked for trying to understand why in the following code: insertion of new node as a child of specific Node do not work. The code is :

public void InsertNodeToTreeLDR(TreeNode newNode)
        {
            var currRoot = Root;
            InsertNodeToTreeHelper(ref currRoot, newNode);           
        }

        private void InsertNodeToTreeHelper(ref TreeNode currTreeRoot, TreeNode newNode)
        {
            if (currTreeRoot == null)
            {
                currTreeRoot = newNode;
                return;
            }

            else if (newNode.Data.CompareTo(currTreeRoot.Data) >= 0)
            {
                var currRootLeftChild = currTreeRoot.Leftchild;
                InsertNodeToTreeHelper(ref currRootLeftChild, newNode);
            }

            else
            {
                var currRootRightChild = currTreeRoot.RightChild;
                InsertNodeToTreeHelper(ref currRootRightChild, newNode);
            }

        }

Note:
I didn't want to include all code here so, this function is part of Tree Class which hold root of type TreeNode.
Think that you already have Tree with root with data == 2 (int), and want to add new left child as with data == 1.
In my implementation the linking between the Node and its child do not work.

JavaSa
  • 5,813
  • 16
  • 71
  • 121
  • "which holds null but probably linked to specific memory address behind the scenes" how can null be linked to a valid memory address? – D Stanley May 20 '14 at 14:34
  • A hold reference to B which is like a "pointer" to address cell of type B and there is null in it, thats how I see it – JavaSa May 20 '14 at 14:35
  • Your goal is unclear. Can you post an example of what you _want_ to do using actual C# code instead of vague pointers? – D Stanley May 20 '14 at 14:36
  • It would be a lot easier to understand your question if you'd give a code *example* rather than describing the code in an (IMO) obscure way. – Jon Skeet May 20 '14 at 14:36
  • So essentially you want a pointer to a pointer like you can do in C++? – D Stanley May 20 '14 at 14:36
  • I will make it more clear, I'm implementing insert to binary search tree in LDR order, will update my code here – JavaSa May 20 '14 at 14:38

2 Answers2

2

You seem to be confused about what passing by reference does and how that interacts with reference types in C#. This code does nothing:

public void InsertNodeToTreeLDR(TreeNode newNode)
{
    var currRoot = Root;
    InsertNodeToTreeHelper(ref currRoot, newNode);           
}

To see why it does nothing, let's step through this one line at a time.

var currRoot = Root;

This line defines a variable called currRoot that is then told to reference the same TreeNode that's referenced by Root. So now currRoot and Root are referring to the same TreeNode instance.

InsertNodeToTreeHelper(ref currRoot, newNode);

Here we're passing the variable currRoot by reference. This means that the InsertNodeToTreeHelper method is allowed to modify the value of currRoot. But remember that the value of currRoot is a reference to a TreeNode, so if the value of currRoot is modified, you're simply telling that specific variable to point somewhere else, it won't do anything to the value of Root (which is also a reference to some TreeNode instance).

If that's not clear, let me try to illustrate this with a simpler example:

public void ClearTree()
{
    var currRoot = Root;
    ClearTreeHelper(ref currRoot);           
}

private void ClearTreeHelper(ref TreeNode currTreeRoot)
{
    currTreeRoot = null;
}

This code example is really the same as just writing this:

public void ClearTree()
{
    var currRoot = Root;
    // ClearTreeHelper       
    currRoot = null;  
}

Hopefully this makes it more clear why your pass by reference doesn't do anything.

Now, for your actual problem, as best I can guess, what you actually want is something like this:

public void InsertNodeToTreeLDR(TreeNode newNode)
{
    if( Root == null )
    {
        Root = newNode;
        return;
    }

    InsertNodeToTreeHelper( Root, newNode );           
}

private void InsertNodeToTreeHelper(TreeNode root, TreeNode newNode)
{
    if (newNode.Data.CompareTo(root.Data) >= 0)
    {
        if( root.LeftChild == null )
        {
            root.LeftChild = newNode;
        }
        else
        {
            InsertNodeToTreeHelper( root.LeftChild, newNode);
        }
    }
    else
    {
        if( root.RightChild == null )
        {
            root.RightChild = newNode;
        }
        else
        {
            InsertNodeToTreeHelper( root.RightChild, newNode);
        }
    }
}

This can also be done without recursion (which I would recommend, I think it would simplify the code immensely and remove the need for a helper method).

Kyle
  • 6,500
  • 2
  • 31
  • 41
  • Thanks for Your patient and thorough answer, I think I got it now! – JavaSa May 20 '14 at 16:13
  • All the confusion is because I thought that `var currRoot = Root; InsertNodeToTreeHelper(ref currRoot, newNode);` equal to `InsertNodeToTreeHelper(ref Root, newNode);` --> I did this workaround because my compiler didn't like the fact I pass property(Root) as ref variable. – JavaSa May 20 '14 at 16:15
  • But just for our talk if I was able to pass property\class data member as ref, it should work as I see it. – JavaSa May 20 '14 at 16:17
  • 1
    Yes, that would work, but I would recommend against it (in this case, not on principle). In my experience I've rarely needed to use `ref` parameters in C# (`out` on the other hand I use more often). – Kyle May 20 '14 at 16:38
  • 1.Great so, when do you think are the rare cases which ref is needed? 2. And If you know how can we do workaround ( good one :) ) for being able to pass property by ref? data member(without property) which is public can be passed by ref, but variable mustn't be public.. – JavaSa May 20 '14 at 16:42
  • (I'm asking because I'm curious how can we get this done by ref- when I have a property.About the solution you wrote - without ref is also very clear and probably what should be done in reality) – JavaSa May 20 '14 at 16:44
0

One problem is that you're passing in a local variable by reference:

var currRootLeftChild = currTreeRoot.Leftchild;
InsertNodeToTreeHelper(ref currRootLeftChild, newNode);

... in the above code, currRootLeftChild is a local variable. If it gets modified at all by the function InsertNodeToTreeHelper then those changes will be thrown away when currRootLeftChild passes out of scope. You need to pass the currTreeRoot's reference, not a local reference, in order for this code to work.

RogerN
  • 3,761
  • 11
  • 18
  • I don't think its the problem as I passed Root(property) to local variable(function parameter) which I pass by reference – JavaSa May 20 '14 at 15:16
  • 1
    @JavaSa Even if that's not the problem, it still doesn't do anything in the given code. Passing a ref parameter to a method allows that method to modify the *value* of the variable that was passed. Since `TreeNode` is presumably a class it's a reference type, so the *value* is a reference, so passing by reference here just allows you to point a variable at a different `TreeNode`. However, you never actually do anything with the result. – Kyle May 20 '14 at 15:29