0

I am trying to return the last node of a binary heap (implemented with pointers, not an array). Here, 'last' means the bottom-most node starting from the left in this case without two children, actually the node where I am supposed to append the new node to. The insert function will bind data to a new node for insertion, then call this function to return the last node, so I can add the new node either left of right depending on the child nodes present, or not.

The problem is that the right side of the tree is always empty, and never gets past the height after root's. Seems to stick on the leftmost side, because it reaches first the exit condition from every recursion call starting from left.

The recursive function checks first the node, returns 0 if no child, returns 1 if only left child and returns 2 in case of a node having two children. Here is the function :

template<typename T>
node<T> * heap<T>::find_insert_pos (node<T> *x, int &res) {
    if(find_insert_poshelper(x, res) == 0) return x;
    else if(find_insert_poshelper(x, res) == 1) return x;
    else {
        node<T> *a = find_insert_pos(x->left, res);
        if(find_insert_poshelper(a, res) != 2) return a;
        else return find_insert_pos(a, res);
        node<T> *b = find_insert_pos(x->right, res);
        if(find_insert_poshelper(b, res) != 2) return b;
        else return find_insert_pos(b, res);
    }
}

I've tried to figure it out, but insertion still goes wrong. The other functions used into insertion are more than triple checked.

(By the way, 'res' is passed by reference always in the chunk of code)


I have changed the logic behind the function. Instead of only validating for children per node, I validate now if the node evaluated had children, if it does then I validate one step further each of those children, left and right, to see if any of those grand-children have children themselves.

If they don't, I will loop this for the next level following the root level 0, jumping to level 1 and so on, until one of the children nodes does not contain two children, and returning x.left or x.right, depending the case.

-- Final edit -- Hard to think about a MRE since it was more about logic. The question was posted by someone in need of practice with recursion, and it happened. All the logic changed, even for sub-functions.

But it will be required to manually assign and narrow down until three levels are full (full meaning having two children) before calling this operation, which is checking three levels down. Having this done nicely I get a beautiful heap.

I can show an attempt to a MRE of how I implemented it to be able to find the bottom node to append a new node to, but not pure since I don't put the code from the 'insert' function, which is part iterative (first three levels) and part recursive (that was the original question, to find the parent node for the new node to insert). How the insert operation goes, I create a new node dynamically and then I search for the parent node where I need to append new data to (the iterative part starts here until the 8th node of the tree is reached, path similar to BFS), then when the position is retrieved (that is, the pointer itself), I test whether for left or right insertion, as by the rules of the heap. Starting at the 8th node, the value of the parent node is set recursively as follows :

First the recursive function itself :

    node * function_a (node *x, int &res) {
    node *temp = function_b (x, res);
    if(temp != ptr_null) return temp;
    else {
        if(x->L != ptr_null) function_a (x->L, res);
        if(x->R != ptr_null) function_a (x->R, res);
        return temp;
    }
}

A sub-function :

    node * function_b (node *x, int &res) {
    node *a = x->L;
    node *b = x->R;
    
    int aL = function_c (a->L, res);
    int aR = function_c (a->R, res);
    int bL = function_c (b->L, res);
    int bL = function_c (b->R, res);
    
    if(aL != 2) return a->L;
    else if(aR != 2) return a->R;
    else if(bL != 2) return b->L;
    else if(bR != 2) return b->R;
    else return ptr_null;
}

And another :

    int & function_c (node *x, int &res) {
    if(x->L == ptr_null && x.R == ptr_null) return res = 0;
    else if(x->L != ptr_null && x->R == ptr_null) return res = 1;
    else return res = 2;
}

Since this is checking 3 levels down from x defined (in this case from the root) in function_a, I can't make it 100% recursive that way or I will get a segmentation fault. How can I improve my algorithm ?

jfo420
  • 11
  • 2
  • 1
    Hi. You need to supply a [mcve]. It's also good to be more specific then *goes wrong*. If you can tell us what the actual output of your MRE is, and the expected output. Have you tried using a debugger to see where things go wrong? – super Aug 21 '21 at 14:25
  • I've tried for two days with the debugger, I'm a beginner as well that can explain why I don't see the bug. The right side of the tree is always empty, and never gets past the height after root's. Seems to stick on the leftmost side, because it reaches first the exit condition from every recursion call starting from left. – jfo420 Aug 21 '21 at 14:53
  • What's your definition of "last"? Maximum element of a min-heap? Right-most element at the bottom level of the tree? Or something else entirely? – pjs Aug 21 '21 at 15:05
  • My 'last' means the bottom-most node starting from the left in this case without two children, actually the node where I am supposed to append the new node to. I am thinking about adding two extra pointers for the siblings left and right for 'lateral' checkup but I feel it's not very elegant doing so. – jfo420 Aug 21 '21 at 15:30
  • 1
    Okay, thanks for clarifying. You should edit and add that to your question so it's self-contained without any need for readers to reference comments to understand. – pjs Aug 21 '21 at 15:36
  • *"The recursive function checks first the node, returns [an integer]"* -- No, your recursive function (one that calls itself) is `find_insert_pos`, which returns a pointer to a node. I think you meant `find_insert_poshelper` in this sentence. – JaMiT Aug 21 '21 at 16:00
  • It might help your debugging if you could focus on a simple, concrete example where this fails to produce the right answer. I'm guessing a 2-node tree would be sufficient? Walk through the code manually and see where the logic fails. – JaMiT Aug 21 '21 at 16:07
  • 2
    Not enough info in the question, but this has some useful answers to a similar question: https://stackoverflow.com/questions/19720438/is-it-possible-to-make-efficient-pointer-based-binary-heap-implementations – Kenny Ostrom Aug 21 '21 at 16:20
  • @KennyOstrom Good link! Several suggestions in the accepted answer could lead to a working solution here. – pjs Aug 21 '21 at 17:39
  • @KennyOstrom wow this is awesome, thanks! – jfo420 Aug 22 '21 at 12:38

0 Answers0