Pointer returns - c++

I am solving a coding challenge. In this challenge, we would be given two linked lists (2 -> 4 -> 3) and (5 -> 6 -> 4) and we have to return the result of their addition (7 -> 0 -> 8).
While I did solve it, I found a better version on Google:
ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
ListNode preHead(0), *p = &preHead;
int extra = 0;
while (l1 || l2 || extra) {
int sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + extra;
extra = sum / 10;
p->next = new ListNode(sum % 10);
p = p->next;
l1 = l1 ? l1->next : l1;
l2 = l2 ? l2->next : l2;
}
return preHead.next;
}
However, I don't understand the step ListNode preHead(0), *p = &preHead;. The address of preHead is being stored in the pointer variable p. In other words, p points to preHead. Then, why is preHead.next being returned in the end? Note that this code does compile and return the expected output.
Appreciate your help!

I like to call it the Dummy Node Pattern. It's where the user will construct an unused node for the purpose of making things like insertion and lookup a lot easier to implement. As you can see in the function, p already points to a valid node to begin with, so there is no need to check if p is NULL and set it to a node of this is true, rather we just append a node using p->next. This is the alternative code where p's starting value is NULL:
ListNode* p = nullptr;
ListNode* tail;
while (l1 || l2 || extra) {
//int sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + extra;
//extra = sum / 10;
if (p != nullptr) {
tail->next = new ListNode(sum % 10);
tail = tail->next;
} else {
tail = p = new ListNode(sum % 10);
}
//l1 = l1 ? l1->next : l1;
//l2 = l2 ? l2->next : l2;
}
return p;
We would have to keep an extra pointer to the end of the list so we know where to insert at each iteration. And we have to make sure p is not a null pointer in the case of inserting for the first time.
The reason preHead.next is returned is because preHead.next is where the insertion begins (it is the head of the actual linked list we want to return).

The following line:
p->next =new ListNode(sum % 10);
Allocates the new node that is returned.
In the first iteration of the loop, *p is the same as preHead. Later iterations move p, but do not invalidate preHead holding a pointer to the first new element added.

Then, why is preHead.next being returned in the end?
Because addTwoNumbers returns a pointer but preHead is a stack variable (i.e. a temporary); returning a temporary reference as a pointer to be de-referenced later is undefined behavior.
However, preHead.next is a heap allocated variable and can then be properly de-referenced when it needs to be.

Related

Code to Find the Merge Point of Two linked Lists

Forward Declaration of FindMergePoint()
int FindMergePoint(Node *Larger,int largeCount,Node *Smaller,int SmallCount);
Function which will count the length of both lists the according to the size passes the lists to FindMergePoint() which will return the node of intersection.
int FindMergeNode(Node *headA, Node *headB)
{
Node *PTRA = headA;
Node *PTRB = headB;
int count1 = 0,count2 = 0;
//Count List One
while(PTRA != NULL){
count1++;
PTRA = PTRA->next;
}
//Count List Two
while(PTRB != NULL){
count2++;
PTRB = PTRB->next;
}
//If First list is greater
if(count1 >= count2){
return FindMergePoint(headA,count1,headB,count2);
}
else{//Second is greater
return FindMergePoint(headB,count2,headA,count1);
}
}
Function Which Takes Larger and Smaller Lists and Finds the merge Point
int FindMergePoint(Node *Larger,int largeCount,Node *Smaller,int SmallCount){
Node *PTRL = Larger;
//Now traversing till both lists have same length so then we can move
parallely in both lists
while(largeCount != SmallCount){
PTRL = PTRL->next;
largeCount--;
}
Node *PTRS = Smaller;
//Now PTRL AND PTRS WERE SYNCHRONIZED
//Now,Find the merge point
while(PTRL->next != PTRS->next){
PTRL = PTRL->next;
PTRS = PTRS->next;
}
return PTRL->data;
}
This code block at FindMergeNode is causing the problem
while(PTRL->next != PTRS->next) {
PTRL = PTRL->next;
PTRS = PTRS->next;
}
Let's say, we have the following entries for PTRL and PTRS
PTRL -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
PTRS -> 17 -> 6 -> 7 -> 8
Now, according to your implementation, PTRL will move ahead 4 times
(length of smaller linked list) and will point to 5. Then, your logic checks whether next of PTRL(which points to 6) is equal to next of PTRS(which points to 6). If they are equal (which they are, because both points to 6), the method returns data of PTRL, which is 5 at that point.
Change condition in while loop to PTRL != PTRS and I think this should solve your problem.

Why use while loop in levelDB's cache (function Resize)?

When I see the implement of levelDB's cache, address. I can not understand why it use while loop in for loop(in function Resize), and I think it can replace by if statement. I hope someone can help me.
void Resize() {
uint32_t new_length = 4;
while (new_length < elems_) {
new_length *= 2;
}
LRUHandle** new_list = new LRUHandle*[new_length];
memset(new_list, 0, sizeof(new_list[0]) * new_length);
uint32_t count = 0;
for (uint32_t i = 0; i < length_; i++) {
LRUHandle* h = list_[i];
while (h != NULL) {
LRUHandle* next = h->next_hash;
uint32_t hash = h->hash;
LRUHandle** ptr = &new_list[hash & (new_length - 1)];
h->next_hash = *ptr;
*ptr = h;
h = next;
count++;
}
}
assert(elems_ == count);
delete[] list_;
list_ = new_list;
length_ = new_length;
}
};
list_ is apparently an array of linked lists. while (h != NULL), combined with h = next (where next is h->next_hash), means the while loop will operate on all the elements of every linked list, stopping only when the last element is reached (when h becomes NULL, either because the list was empty or because next_hash of an element was NULL).
If you replaced it with if (h != NULL), it would only work on the first element of the linked list.
It looks like list_ is a dynamic array of singly linked lists.
I assume the list_ looks something like the following
list_[0]-> node_1 -> node_2 -> null
list_[1]-> node_3 -> null
list_[2]-> null
....
list_[n]-> node_m-1 -> node_m -> null
To properly copy all of the elements into new_list you need to use the while loop. Otherwise any element that is not directly addressable from list_ will not be copied/hashed into the new_list. In the above diagram that would mean node_2 and node_m+1 would not be added to the new_list.
The new_list will keep the same shape but should have fewer collisions.
Using an if statement the new_list would look something like:
new_list[0]-> node_1 -> null
new_list[1]-> null
new_list[2]-> node_2 -> null
...
new_list[p-1]-> node_k -> null
new_list[p] -> null
That is each item in new_list would point to a list of 1 or zero elements.
Note node_1 in this diagram isn't necessarily the same as node 1 in the above diagram.
Using an If statement instead of a while loop will also lead to a memory leak since you can no longer access all of the elements.
Variable list_[i] has a sub list, while inside the for loop is looping over the sub list.
The if-statement doesn't work, if you have two elements list_[i] and list_[j] are both hashed to a same index new_list[m]. In such a case, you have to use while-statement to merge two buckets. Meanwhile, the length of every bucket in this implementation is less than 1 on average, so the while-statement here is actually as fast as the if-statement.

Trying to sort a linked list using a merge function?

I have written a function to merge two singly linked lists. For example, if A = 1 2 3 and B = 3 4 5 and I merge them both, I get A = 1 2 3 3 4 5 and B = NULL. What I want to do now is to write a function which sorts a singly linked list using the mergesort algorithm (somehow using my merge function). For mergesort, if I'm not wrong, I would have to break the linked list in half in some way and then do the rest of the work. I have a small outline written down on how I want to do it. I'm not sure how I would go about doing the splitting at the moment. Any help is appreciated!
List mergeSort(List L) {
if(|L| > 1) {
split L into L1 and L2;
L1 = mergeSort(L1);
L2 = mergeSort(L1);
return(merge(L1,L2));
}
}
My merge function below:
void mylist::merge(mylist& b)
{
if (!this->isSorted() || !b.isSorted())
cout << "error" << endl;
Node* ptr1 = b.head;
Node* prev_a = NULL;
Node* curr_a = head;
Node* curr_b = ptr1;
while (curr_b) {
if (curr_a && head->key < ptr1->key) {
prev_a=curr_a;
curr_a = curr_a->next;
}
else {
Node* b_next = curr_b->next;
curr_b->next = curr_a;
if (prev_a) prev_a->next = curr_b;
else head = curr_b; // curr_b is first element in 'a'
prev_a = curr_b;
curr_b = b_next;
}
return;
}
To divide the list into two halves, two pointers can be used.
Both pointers start at the head of the list. One pointer move every two steps, while the other
move one step each time.
When the fast pointer reach null, the slower pointer will points to the middle of the list.
ListNode *fast(head->next), *slow(head);
while(fast && fast->next) {
fast = fast->next->next;
slow = slow->next;
}

Binary tree interview: implement follow operation

I was asked to implement a binary search tree with follow operation for each node v - the complexity should be O(1). The follow operation should return a node w (w > v).
I proposed to do it in O(log(n)) but they wanted O(1)
Upd. It should be next greater node
just keep the maximum element for the tree and always return it for nodes v < maximum.
You can get O(1) if you store pointers to the "next node" (using your O(log(n) algorithm), given you are allowed to do that.
How about:
int tree[N];
size_t follow(size_t v) {
// First try the right child
size_t w = v * 2 + 1;
if(w >= N) {
// Otherwise right sibling
w = v + 1;
if(w >= N) {
// Finally right parent
w = (v - 1) / 2 + 1;
}
}
return w;
}
Where tree is a complete binary tree in array form and v/w are represented as zero-based indices.
One idea is to literally just have a next pointer on each node.
You can update these pointers in O(height) after an insert or remove (O(height) is O(log n) for a self-balancing BST), which is as long as an insert or remove takes, so it doesn't add to the time complexity.
Alternatively, you can also have a previous pointer in addition to the next pointer. If you do this, you can update these pointers in O(1).
Obviously, in either case, if you have a node, you also have its next pointer, and you can simply get this value in O(1).
Pseudo-code
For only a next pointer, after the insert, you'd do:
if inserted as a right child:
newNode.next = parent.next
parent.next = newNode
else // left child
predecessor(newNode)
For both next and previous pointers:
if inserted as a right child:
parent.next.previous = newNode
newNode.next = parent.next
parent.next = newNode
else // left child
parent.previous.next = newNode
newNode.previous = parent.previous
parent.previous = newNode
(some null checks are also required).

interleave 2 linked list C++

I have the solution code here:
// Pre-condition: The fronts of two linked lists are provided.
// Post-condition: A linked list is returned that is the result of
// interleaving the elements from each provided list.
// (e.g. {1, 2, 3} & { 4, 5, 6} would return {1, 4, 2, 5, 3, 6}
Node* interleave( Node*& front1, Node*& front2 ) {
if( !front1 ) return front2;
if( !front2 ) return front1;
Node* third = front1->next; //this will become the third element
Node* fourth = front2->next; // this will be come the fourth element
front1->next = front2;
front2->next = third;
third = interleave(third, fourth);
return front1;
}
I kind of understand it but i would never be able to come up with something like this since i'm very bad at recursion. Is there another way to do this problem non-recursively? if so could you give me a hint? I tried this:
Node* interleave( Node*& front1, Node*& front2 ) {
Node* newNode = new Node;
while(front1!=NULL && front2!=NULL){
newNode = front1->next;
newNode = front2->next;
front1 = front1->next;
front2 = front2->next;
}
return newNode;
}
I'm sure it's wrong but that's the only thing i can come up with right now. Please help. Thank you
Try drawing two linked lists in parallel on a sheet of paper. Put some numbers in the nodes, just to tell them apart. Consider how you would reconnect them to form a single list, starting at the head (or "front") and working down. Note that you have to keep track of a few special nodes, like the first node of the resultant list and a couple of others. The pattern should become clear.
(Note that there's no need to construct a new node with new.)
There are a few mistakes in your code:
Node* interleave( Node*& front1, Node*& front2 )
I don't see the need for a reference to a pointer, since the first item in front1 will keep on being the first, and you don't need to mess with front2 at all.
Node* newNode = new Node;
while(front1!=NULL && front2!=NULL){
newNode = front1->next;
This is causing a memory leak - you're allocating at least sizeof(Node) bytes, but then you're losing the reference to the pointer, and you won't be able to delete it anymore.
Also, you're not doing anything with newNode, so you might throw it away as well.
front1 = front1->next;
front2 = front2->next;
Basically you're telling that front1 will rather point to the next element, and since you passed a reference to front1, you're altering the real pointer. Eventually, front1 or front2 will be NULL and the loop will terminate, so at least one of the two given parameters will become useless. You're never changing next, so the order will be left unchanged - you're just walking through the lists.
One approach could be to set front2's value to front1->next, then swap pointers and iterate again:
Node *a = front1, *b = front2;
while (a && b) {
Node* tmp = a->next;
a->next = b;
b = tmp;
a = a->next;
}
return front1;
I didn't test this, but it should be close to working. You can replace the verbose swap code with std::swap() if you're using stl.
The idea is simple: suppose you have two lists:
A -> B -> C -> NULL
D -> E -> F -> NULL
you say that A's next item is going to be the first element in the second list, so D:
A -> D -> E -> F -> NULL
and then the second lists becomes the ancient A's successor, so just B -> C -> NULL. You then advance a to point to its new next, or D, so you now have:
D -> E -> F -> NULL
B -> C -> NULL
and you repeat:
D -> B -> C -> NULL
E -> F -> NULL
B -> C -> NULL
F -> NULL
and so on until a NULL is met. Then front1, that still points to A, should have the right sequence (that is, unless I'm terribly wrong :p )