Ștefan Tătărucă
Ștefan Tătărucă

Reputation: 57

Binomial heap sibling - linked list reversal

I don't understand the reversal of the list of a node l in a binomial heap:

Node* reverseList(Node* l) {
    //return reverseNode(l);
    if(l->sibling)
    {
        return reverseList(l->sibling);
        l->sibling->sibling = l;
    }
}

What does this mean? :

l->sibling->sibling = l;

The parent?

Upvotes: 2

Views: 132

Answers (2)

trincot
trincot

Reputation: 350300

A return statement ends the execution of the function, so you are asking about dead code.

I would expect the function to actually be like this:

Node* reverseList(Node* l) {
    if (l->sibling)
    {
        Node* head = reverseList(l->sibling);
        l->sibling->sibling = l;
        l->sibling = NULL;
        return head;
    }
    return l;
}

To visualise this, let an example linked list consist of three nodes:

  l
  ↓
┌───────────────┐     ┌───────────────┐     ┌───────────────┐
│ sibling: ─────────► │ sibling: ─────────► │ sibling: NULL │
│               │     │               │     │               │
└───────────────┘     └───────────────┘     └───────────────┘ 

When the function is called, we get into the if and make a recursive call. That new (second) execution context has its own local variables, and to distinguish them, I will add an accent to their names. So we have another l' variable:

  l                      l'
  ↓                      ↓
┌───────────────┐     ┌───────────────┐     ┌───────────────┐
│ sibling: ─────────► │ sibling: ─────────► │ sibling: NULL │
│               │     │               │     │               │
└───────────────┘     └───────────────┘     └───────────────┘ 

Also that function's execution will make a recursive call:

  l                      l'                   l"
  ↓                      ↓                    ↓
┌───────────────┐     ┌───────────────┐     ┌───────────────┐
│ sibling: ─────────► │ sibling: ─────────► │ sibling: NULL │
│               │     │               │     │               │
└───────────────┘     └───────────────┘     └───────────────┘ 

The latest (third) execution of the function gets l'->sibling as argument and will assign that to its own local variable l". It will find that l"->sibling is NULL, and so it just returns the same pointer without making any alteration. At this moment the lifetime of the variable l" ends. The caller assigns the returned value to a local head' variable -- again the accent to make clear this happens in the second execution context:

  l                      l'                  
  ↓                      ↓                   
┌───────────────┐     ┌───────────────┐     ┌───────────────┐
│ sibling: ─────────► │ sibling: ─────────► │ sibling: NULL │
│               │     │               │     │               │
└───────────────┘     └───────────────┘     └───────────────┘ 
                                              ↑
                                             head'

Now we get to the statement: l'->sibling->sibling = l'. That means an assignment is made to the sibling member of the last node, and so we get:

  l                      l'                  
  ↓                      ↓                   
┌───────────────┐     ┌───────────────┐     ┌───────────────┐
│ sibling: ─────────► │ sibling: ─────────► │ sibling: ─┐   │
│               │     │               │ ◄───────────────┘   │
└───────────────┘     └───────────────┘     └───────────────┘ 
                                              ↑
                                             head'

Then we execute l'->sibling = NULL:

  l
  ↓ 
┌───────────────┐     ┌───────────────┐     ┌───────────────┐
│ sibling: ─────────► │ sibling: NULL │     │ sibling: ─┐   │
│               │     │               │ ◄───────────────┘   │
└───────────────┘     └───────────────┘     └───────────────┘ 
                                              ↑
                                             head'

Then we execute return head'. The variables of the second execution context end their lives (no more accents). The first execution context will assign the returned pointer to its own head variable:

  l
  ↓ 
┌───────────────┐     ┌───────────────┐     ┌───────────────┐
│ sibling: ─────────► │ sibling: NULL │     │ sibling: ─┐   │
│               │     │               │ ◄───────────────┘   │
└───────────────┘     └───────────────┘     └───────────────┘ 
                                              ↑
                                             head

Now we get to the statement: l->sibling->sibling = l. That means an assignment is made to the sibling member of the middle node, and so we get:

  l
  ↓ 
┌───────────────┐     ┌───────────────┐     ┌───────────────┐
│ sibling: ─────────► │ sibling: ─┐   │     │ sibling: ─┐   │
│               │ ◄───────────────┘   │ ◄───────────────┘   │
└───────────────┘     └───────────────┘     └───────────────┘ 
                                              ↑
                                             head

We execute l->sibling = NULL:

  l
  ↓ 
┌───────────────┐     ┌───────────────┐     ┌───────────────┐
│ sibling: NULL │     │ sibling: ─┐   │     │ sibling: ─┐   │
│               │ ◄───────────────┘   │ ◄───────────────┘   │
└───────────────┘     └───────────────┘     └───────────────┘ 
                                              ↑
                                             head

And finally, we return head. The local variables end their lifetimes, and so only the returned pointer is relevant:

┌───────────────┐     ┌───────────────┐     ┌───────────────┐
│ sibling: NULL │     │ sibling: ─┐   │     │ sibling: ─┐   │
│               │ ◄───────────────┘   │ ◄───────────────┘   │
└───────────────┘     └───────────────┘     └───────────────┘ 
                                              ↑
                                             (returned)

You can see that the returned pointer is indeed referencing the reversed list.

Upvotes: 2

Deepthi Tabitha Bennet
Deepthi Tabitha Bennet

Reputation: 1146

The code in the question is incorrect, this is the correct code

int RevertList(Node *h){
    if (h->sibling != NULL){
        RevertList(h->sibling);
        (h->sibling)->sibling = h;
    }
    else
        root = h;
}

RevertList is a helper-function used when a node is deleted from a Binomial Heap.

When a node is deleted, it’s child and their siblings are detached from the Binomial Heap Structure. The RevertList function reverses the order of the detached children, so they can be union-ed to the root list, in the correct order.

Take a look at this code for better understanding of how this works!

Below is an example, from the CLRS Textbook

enter image description here

Upvotes: 2

Related Questions