Why does Infinite loop occurs while reversing the linked list using recursion - pointers

I am a beginner in data structures. Lets assume that I have a linked list of 5 elements. I was writing the below code to reverse the linked list using recursion:
void reverse (node* p)
{
if (p->next == NULL)
{
head = p;
return;
}
reverse (p->next);
node* q = p->next;
q->next = p;
p->next = NULL;
}
In the above code, head node is passed initially as an argument. This code runs well;but the question is why are we using the line?
p->next = NULL;
If I did not add that line, it becomes an infinite loop. But even if that line is not added, p->next is assigned with the previous node's address in the following stack unwinding. So why does it cause an infinite loop if that line is not added?

Related

Convert A Given Binary Tree To Doubly Linked List

The problem statement is:
Given a Binary Tree, convert this binary tree to a Doubly Linked List.
A Binary Tree (BT) is a data structure in which each node has at most two children.
A Doubly Linked List contains a previous pointer, along with the next pointer and data.
The order of nodes in Doubly Linked List must be the same as Inorder of the given Binary Tree.
The doubly linked list should be returned by taking the next pointer as right and the previous pointer as left.
You need to return the head of the Doubly Linked List.
For example:
4
/ \
2 5
/ \
1 3
The doubly linked list would be: 1 2 3 4 5
My code is:
class BinaryTreeNode
{
public :
T data;
BinaryTreeNode<T> *left;
BinaryTreeNode<T> *right;
BinaryTreeNode(T data) {
this -> data = data;
left = NULL;
right = NULL;
}
};
void inorder(BinaryTreeNode<int>* root,BinaryTreeNode<int>* &prev,BinaryTreeNode<int>* &nroot){
if(!root) return;
inorder(root->left,prev,nroot);
if(prev == NULL) nroot=root;
else{
root->left = prev;
prev->right=root;
}
prev=root;
inorder(root->right,prev,nroot);
}
BinaryTreeNode<int>* BTtoDLL(BinaryTreeNode<int>* root) {
BinaryTreeNode<int>* prev=NULL;
BinaryTreeNode<int>* nroot=NULL;
inorder(root,prev,nroot);
return nroot;
}
I have doubt regarding root.
The root pointer works with passing by value and does not works when it is passed by reference.
When root is passed by reference, it does not work.
void inorder(BinaryTreeNode<int>*& root,BinaryTreeNode<int>*& prev,BinaryTreeNode<int>* &nroot){
if(!root) return;
inorder(root->left,prev,nroot);
if(prev == NULL) nroot=root;
else{
root->left = prev;
prev->right=root;
}
prev=root;
inorder(root->right,prev,nroot);
}
How can I know which variable should be passed by reference and which variable should by passed by value with regard to pointers?
At first glance, one problem is the API of inorder itself. You are assigning nroot = root; to see why this is a problem, consider this simpler example:
void set_x(int *x, int *y)
{
x = y;
}
Remember that pointers are really just memory addresses. So, the assignment of x = y says, "replace the memory address that x contains, and set it to whatever y contains". At no stage do you actually change the value at the memory address.
Now, considering nroot = root again, here you are just giving the local variable you have a new memory address, but not updating anything. So at your call side BTtoDLL, you provide it nullptr for the address, to which it never uses it, and never sets it. So, BTtoDLL will never see any change to nroot.

Why do I need to set both tail and tail->next to node to create a sorted merged list?

I've found a nifty block of code to create a sorted merged list. However, there are two lines of code that I can't wrap my head around:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode dummy(0);
ListNode *tail = &dummy;
while(l1 && l2) {
ListNode *& node = l1->val < l2->val? l1 : l2;
tail->next = node;
tail = node;
node = node->next;
}
tail->next = l1 ? l1 : l2;
return dummy.next;
}
Why do we need to set tail->next = node before setting tail = node? I noticed that "tail = node" overwrites the assignment in the preceding line regardless.
But I've also noticed that my code breaks if I don't have "tail->next = node."
Thanks!
I think I answered my own question. In the first iteration of the while loop, tail->next=node is setting the dummy node's next address to node.
The following line, tail=node, is setting the tail itself to node. After doing this, you lose access to changing the dummy node's pointers, so you have to set this beforehand.

Linked List: Copy List Using Recursive

I am new to Linked List. I am trying to write a CopyList() code that can copy a linked list to a new list. There's a unique version using recursive and I don't really understand:
struct node
{
int data;
struct node *next;
};
struct node* CopyList(struct node* head) {
struct node* current = head;
if (current == NULL) return NULL;
else {
struct node* newList = malloc(sizeof(struct node));
newList->data = current->data;
newList->next = CopyList(current->next); // recur for the rest
return(newList);
}
}
My trouble of understanding is the line newList->next = CopyList(current->next);
So how does this work for copying and why?
Lets take an example. If you simply put the current->next in newList->next
i.e
newList->next = current->next. Then it will point to the next node of old list only. Not to the next node of new list.
So to make a different list (Copy list). You separately have to make a new node and return it to point to next of previous node.
This is the magical recursive statement.
newList->next = CopyList(current->next);
For each recursive step, this will delegate the task of creating remaining linked list, to the next recursive call.
For example: List is getting created from right to left.
CopyList (1->2->3->4->5)
|
|---------1-> CopyList (2->3->4->5)
|
|---------2-> CopyList (3->4->5)
|
|---------3-> CopyList (4->5)
|
|---------4-> CopyList (5)
|
|---------5-> CopyList (NULL)
Returns 5
Returns 4->5->NULL
Returns 3->4->5->NULL
Returns 2->3->4->5->NULL
Returns 1->2->3->4->5->NULL
As per wiki
A simple base case (or cases)—a terminating scenario that does not use recursion to produce an answer.
A set of rules that reduce all other cases toward the base case.
In your case, terminating scenario is if list reaches the end, just return null and a new node is created at every step that leads the list to the base scenario.
This is the recursion step. The previous two commands create a new node and copy the head of the current list to that object. Now, instead of iterating (looping) through the rest of the list, we call CopyList to copy the remainder of the list -- everything except the head node that we just copied.
CopyList returns a copy of that remainder, which we simply append to the copy of the head node ... and we're done.

D: Strange behaviour from std.container.BinaryHeap with custom function for comparison

I've written the following code for a heap of Node*s, which are found in module node:
import std.exception, std.container;
public import node;
alias NodeArray = Array!(const (Node)*);
alias NodeHeap = BinaryHeap!(NodeArray, cmp_node_ptr);
auto make_heap() {
return new NodeHeap(NodeArray(cast(const(Node)*)[]));
}
void insert(NodeHeap* heap, in Node* u) {
enforce(heap && u);
heap.insert(u);
}
pure bool cmp_node_ptr(in Node* a, in Node* b) {
enforce(a && b);
return (a.val > b.val);
}
I then tried running the following unit tests on it, where make_leaf returns a Node* initialized with the argument given:
unittest {
auto u = make_leaf(10);
auto heap = make_heap();
insert(heap, u); //bad things happen here
assert(heap.front == u);
auto v = make_leaf(20);
insert(heap, v);
assert(heap.front == u); //assures heap property
}
The tests make it to the line I comment-marked, and then throw an enforcement error on the line enforce(a && b) in cmp_node_ptr. I'm totally lost as to why this is happening.
you are doing wrong thing in this operator:
NodeArray(cast(const(Node)*)[])
you obviously want to create empty NodeArray, but what you really got is NodeArray with one null item. NodeArray constructor takes list of values for new array as arguments, and you passing one "empty array" (which is essentially null), thus creating NodeArray with one null element.
the correct way is just:
NodeArray()
i.e.:
auto make_heap() {
return new NodeHeap();
}
make this change and everything will be fine.
p.s. it seems that D notation for multiple arguments of type U (U[] values...) made you think that constructor accepts another array as initialiser.
p.p.s. sorry, fixed make_heap() code: accidentally forgot to write "NodeArray()" in it. and edited it again, as empty NodeArray() call is not necessary there. double fault!

reverse linked list - Recursion

Sorry if this is a very basic question, I am just trying to learn recursion.
The below code can reverse a linked list.
I understand the logic until line 3, but I am confused when line 4 will be called (n.next=prev) since the function gets called again before executing this line.
Can someone let me know the flow of this recursion?
void reverse(node n, node prev) {
if (n == null) { newroot = prev; return; }
reverse(n.next, n);
n.next = prev;
}
As soon as n hits null and reverse function return it will backtrack from there to it's calling function all the way to it's first calling function.
UPDATE: See the comments below for a more complete explanation.

Resources