Understanding reference arguments in recursion - c++

I have tried implementing the code for Sorted Linked List to BST from leetcode
https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/ .
The approach which I have used to use a recursive approach like below. But here we have to use reference (&) in head in the function argument. If I don't use, then output will not be correct and gives wrong answer. I am not able to grasp why reference to head is needed here or in what type of recursion scenarios we should do that. I sometimes get confused in recursion.
int countNodes(ListNode* head) {
int count = 0;
ListNode *temp = head;
while (temp != NULL) {
temp = temp->next;
count++;
}
return count;
}
TreeNode *sortedListUtil(ListNode *&head, int n) {
// head should be ref, if we dont use & ,
// unexpected output will come
if (n <= 0)
return NULL;
TreeNode *left = sortedListUtil(head, n/2);
TreeNode *root = new TreeNode(head->val);
root->left = left;
head = head->next;
root->right = sortedListUtil(head, n - n/2 -1);
// recur for remaining nodes
return root;
}
TreeNode* sortedListToBST(ListNode* head) {
if (head == NULL)
return NULL;
int n = countNodes(head);
return sortedListUtil(head, n);
}
Input linked List is : head = [-10,-3,0,5,9]
Output of BST should be this if I use & in head in function argument : [0,-3,9,-10,null,5]
If I don't use '&' in function argument then the tree constructed will be :
[-10,-10,-3,-10,null,-3] which is wrong. Root Node should be 0.

sortedListUtil does two things: it returns the root (1), and it also changes the head (2) so that its invocations are advancing along the list from call to the other recursive call:
TreeNode *sortedListUtil(ListNode *&head, int n) {
// head should be ref, if we dont use & ,
// unexpected output will come
if (n <= 0)
return NULL;
TreeNode *left = sortedListUtil(head, n/2);
TreeNode *root = new TreeNode(head->val); // <<<<------ NB (3)
root->left = left;
head = head->next; // <<<<--------------------- NB (2)
root->right = sortedListUtil(head, n - n/2 -1);
// recur for remaining nodes
return root; // <<<<--------------------- NB (1)
}
Without changing the head, each invocation of sortedListUtil would look at the same element in the input linked list -- its head element.
But this way, for each element that is put into a ListNode by TreeNode *root = new TreeNode(head->val); (3), the head is advanced so that the next element from the list will be the one that gets put into the next constructed ListNode.
Since head is function's parameter, it must be passed by reference & so the change is seen by the caller; otherwise the variable would be local to the function invocation and the change would not be seen by the caller.
Since we've used the list's element, we must advance the pointer into the list, so that the next list's element is the one that goes next into the next node.
edit: Where does a given sortedListUtil invocation change head? How many times? Just once! So whatever is done within the "left" invocation(s), the head is advanced; then we take one element (the one we're at, after the left is filled), advance head one notch accordingly, and let the "right" invocation(s) fill the right subtree!
Recursion works like this: assume it works; conclude it works for the smaller case(s) (here, left and right) by the hypothesis (and also, for the smallest case -- where we just return NULL and do not touch the head); see that adding small change by this invocation doesn't break things (it doesn't, we properly advance head one notch); then conclude it works overall!

Related

Insert a new node in an ordered linked list in C++

I am writing some code in visual studio with c++, it's an ordered linked list but I am having a bit of trouble with the pointers.
I have three different methods / functions that carry out this task.
/*
* insert_head: Insert a node at the beginning of the list.
*/
book *inserta_head(book *head, book *newNode){
newNode->next = head;
return newNode;
}
/*
* insert_after: Insert a new node after another one.
*/
void insert_after(book *node, book *newNode){
newNode->next = node->next;
node->next = newNode;
}
/*
* insert: Adds a new node (ordered by code) to the list.
*/
void insert(book* head, int code, char name[40], char lastName[40], char title[40], int year, int lend) {
book* newNode = crear_libro(code, name, lastName, title, year, lend);
book* aux = head;
// If the list is empty.
if (head == NULL){
head = insert_head(head, newNode);
} else {
// If the new node goes before the head.
if (aux->code > newNode->code){
head = insert_head(head,newNode);
} else {
while (aux != nullptr && aux->code < newNode->code)
aux = aux->next;
// Verify the code isn't repeated
if (aux != nullptr && aux->code == newNode->code){
printf("Error: Verify the code. \n");
} else {
insert_after(aux,newNode);
}
}
}
}
I've tried running the code. Every time I try to print the list it says it's empty. I've checked my printing method and the method that creates nodes, both of them are working so I'm pretty sure it is related to the pointers but I can't find the error.
Your insert function changes the head pointer. But that pointer is a copy of the head pointer you called the function with. So the head pointer outside the insert function is unchanged. That's why nothing gets added to the list.
One simple fix is to make the head parameter a reference.
void insert(book*& head, int code, ...
The problem is how you handle the head.
After this line:
head = insert_head(head, newNode);
head in the function should be correct (double check with a debugger).
However, the head in the caller will remain unchanged. This is because you don't change the data in the existing head, but you create a new one.
A simple fix is to take the pointer to the pointer to head. book** head This way you can change the pointer in the caller as well (after fixing all the compilation errors).

Using an array of pointers-to-pointers to manipulate the pointers it points to (C++)

I've been doing this as an exercise on my own to get better at C++ (messing around with a linked list I wrote). What I want to do is to reverse the list by twisting the pointers around, rather than just 'printing' the data out in reverse (which is relatively straightforward).
I have an array of pointers-to-pointers, each pointing to a node in a linked list. But this is less a question about linked-list dynamics (which I understand), and more about pointer magick.
A node looks like this,
template<class T>
struct node {
T data;
node *next;
node(T value) : data(value), next(nullptr) {}
};
And the code in question,
node<T> **reverseArr[listLength];
node<T> *parser = root;
for (auto i : reverseArr) {
i = &parser;
parser = parser->next;
}
root = *(reverseArr[listLength - 1]);
for (int ppi = listLength - 1; ppi >= 0; --ppi) {
if (ppi == 0) {
(*reverseArr[ppi])->next = nullptr;
//std::cout << "ppi is zero!" << "\t";
}
else {
(*reverseArr[ppi])->next = (*reverseArr[ppi - 1]);
//std::cout << "ppi, 'tis not zero!" << "\t";
}
}
My logic:
The new root is the last element of the list,
Iterate through the array in reverse,
Set the current node's next pointer to the previous one by setting the current node's nextNode to the next node in the loop.
What's happening:
If I leave the debug print statements commented, nothing. The function's called but the linked list remains unchanged (not reversed)
If I uncomment the debug prints, the program seg-faults (which doesn't make a whole lot of sense to me but seems to indicate a flaw in my code)
I suspect there's something I'm missing that a fresh pair of eyes might catch. Am I, perhaps, mishandling the array (not accounting for the decay to a pointer or something)?
You're overthinking the problem. The correct way to reverse a single-linked list is much simpler than you think, and does not involve arrays at all.
All you need to do is walk through the list setting each node's next pointer to the head of the list, then set the head of the list to that node. Essentially, you are unlinking each node and inserting it at the start of the list. Once you reach the end, your list is reversed.
It just requires a bit of care, because the order that you do things is important. Something like this should do it:
template <class T>
node<T> * reverse( node<T> * head )
{
node<T> *current = head;
head = NULL;
while( current != NULL )
{
// store remainder of list
node<T> *remain = current->next;
// re-link current node at the head
current->next = head;
head = current;
// continue iterating remainder of list
current = remain;
}
return head;
}
The operation has a linear time complexity. You would invoke it by passing your list's head node as follows:
root = reverse( root );
It should go without saying that it would be a bad idea to call this function with any node that is not the head of a list, or to pass in a list that contains cycles.

swapping 2 nodes in a linked list c++

I'm trying to swap 2 adjacent nodes in a linked list (75 and 9 in this case), and every time I run the code, say with a linked list of 75->9->767->2..., I get the whole list just turning to 75->9->75->9->75->9, etc.. I have to update pointers
Your problem is with the lines
nextPtr->next = tempPtr;
nextPtr = tempPtr;
I'm not sure, but i think you only mean to type
nextPtr = tempPtr;
instead.
I guess you are looking for pairwise swap, use this for the same. Let me know if it went fine.
for 75->9->767->2 it produces 9->75->2->762... If you want something different but similar, you can use it and make changes accordingly.
void swap(struct node **head)
{
if (*head == NULL || (*head)->next == NULL)
return;
struct node *prev = *head;
struct node *cur = (*head)->next;
*head = cur;
while (true)
{
struct node *next = cur->next;
cur->next = prev;
if (next == NULL || next->next == NULL)
{
prev->next = next;
break;
}
prev->next = next->next;
prev = next;
cur = prev->next;
}
}
Hint: If you want to swap nodes H (what you're calling hdList) and N (nextPtr) in a linked list you have to make whatever points to H now point to N. You're not keeping track of whatever points to H at all.
That is, suppose you know that part of your list is
... P -> H -> N -> Q ...
and you want to swap H and N. The state of the list after the swap should be
... P -> N -> H -> Q ...
right? But you can't do this because you don't know what used to point to H (i.e. P) so you can make it point to N.
I think you're going to have to go back to the drawing board on this one.
If you want to swap 2 nodes in linked list, why are you trying to swap the pointers and all? Just swap the data in it with the simple swap logic. let the pointers be as it is. If this is not what you want, tell me in detail what exactly you want it to be.

Return a pointer to a sorted list; linked list in C++

i want this function sortPair to take 2 Node pointers and return a pointer to a list of the 2 elements sorted alphabetically. The code below is what I have so far. If someone could let me know where I went wrong, that would be great.
struct Node{
string val;
Node* next;
};
Node* sortPair (Node* p1, Node* p2){
//Assert that neither pointer is null
assert(p1!=NULL);
assert(p2!=NULL);
Node* head=NULL;
Node* current=NULL;
Node* last = NULL;
current = new Node();
if(p1-> val >p2-> val) //If p1->val comes before p2->val in the alphabet
{
current->val = p1->val;
head = current;
last = current;
current = new Node();
current -> val = p2->val;
last = current;
last ->next = NULL;
}
else
{
current->val = p2->val;
head = current;
last = current;
current = new Node();
current -> val = p1->val;
last = current;
last ->next = NULL;
}
return head;
}
A linked list is just a series of nodes that are linked by each element having a pointer to the next one.
From your code, it seems like you do not want to make a list of the two nodes, but rather insert a node into a list that already exists.
If all you want to do is to make a linked list of the two nodes that are there, then set the one with the lower or higher value, depending on how you sort them, to point at the other one. For example, if you are sorting from smallest to biggest, set the smallest node's next pointer to point to the bigger one and return the pointer of the smallest one.
If you want to add one of the nodes into a list of nodes, then you must loop through the list until you find one that is larger or smaller than the node you want to insert. I recommend using a while loop.
If you want to merge two lists, then you must make a new loop that inserts each element of one list into the other list.
There is no need to make a new node for any of this, just use the ones you have and change the next pointers.
Hope this helps.

Algorithm for creating a "relative" priority queue? (c/c++)

I want to make a queue using linked lists.
There are numerous algorithms out there for that. But what i'm curious in is how to make a relative priority queue.
Maybe there is a special name for this type of queue, but i don't know it, and i haven't had any luck googling for the solution.
Anyways, let's say i have this struct, which will represent the Node of my list.
struct Node {
int value;
Node* next;
}
if i want to create a priority queue (where the element with the least value is first), when i insert for example 5 7 1 8 2, my list should look like this:
1 -> 2 -> 5 -> 7 -> 8
It's not really hard to implement that.
What i want to do is - when i insert the first element, other elements should have value relative to the previous element. So, in my example, the list/queue would contain the following values:
1 -> 1 -> 3 -> 2 -> 1
I'm not really sure how i would implement that? Would the following idea be applicable:
in the Node struct i add another field, which would represent the original value.
i find the position of the node i'm inserting the same way i would do when creating an ordinary linked list, and then i just say
temp->value = temp->originalValue - previous->originalValue;
You need to store extra data in each node, either the relative priority, or a "previous" pointer. Since the next node's relative priority needs to updated whenever a node is removed (how to do that without a prev pointer?), I suggest the "previous" pointer:
struct Node {
int value;
Node* next;
Node* prev;
}
Then a function can evaluate the relative priority:
int relative_priority(Node* node) {
if (node == NULL)
return 0;
if (node->prev == NULL)
return node->value;
return node->value - node->prev->value;
}
Note that I'm using C, you'll need to replace NULL with 0 for C++
You first have to identify where to insert the new node. This involves decrements on the target value, adjusting its relative value in relation to the current in the list. At the point of insertion, you have to point the previous node to the new node, and then adjust the node ahead of the new node with a new relative value.
Node * create_node (int value, Node *next) { /* ... */ }
void insert_relative_priority_queue (Node **head, int value) {
Node **prev = head, *cur;
if (*head) {
cur = *head;
while (value > cur->value) {
value -= cur->value;
prev = &cur->next;
cur = cur->next;
if (cur == 0) break;
}
*prev = create_node(value, cur);
if (cur) {
cur->value -= value;
}
} else {
*head = create_node(value, 0);
}
}
When you remove from the front of the list, you adjust the value of the new head:
void remove_relative_priority_queue (Node **head) {
if (*head) {
Node *cur = *head;
*head = cur->next;
if (*head) {
(*head)->value += cur->value;
}
free(cur);
}
}