interleave 2 linked list C++ - 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 )

Related

How to reverse a linked list

I was working on Stack Overflow and came up across the #92.
Reverse a linked list 2 question. This is the question's description:
Given the head of a singly linked list and two integers left and right
where left <= right, reverse the nodes of the list from position left
to position right, and return the reversed list. For example, given
the linked list [1,2,3,4,5] 1, 4 the list should become [4,2,3,1,5]
It works for all runs but my code produces the wrong answer for one test case, which doesn't make sense. given. [1,2,3,4] 1,4 with 1 being left position an 4 being right position what makes sense for the list to become is [4,2,3,1] which is what my code produces. The correct answer they display is [4,3,2,1] which is screwing with my head and I can't understand why it's doing that. Any heads up are appreciated.
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right)
{
int x = 1;
ListNode * left_node = nullptr;
ListNode * right_node = nullptr;
ListNode * curr = head;
int temp = 0;
if (!head)
return nullptr;
while(curr)
{
if(x == left)
left_node = curr;
if(x == right)
right_node = curr;
curr = curr->next;
++x;
}
temp = left_node->val;
left_node->val = right_node->val;
right_node->val = temp;
return head;
}
Your solution implements swapping the values for the 2 indexes left and right, which matches the example given in the question.
But the question was to reverse the list between left and right, not just swap the two end points. So 1,2,3,4 becoming 4,3,2,1 is the correct solution and both the example and your solution are wrong, they only swap the entpoints.
PS: Most languages start counting at 0.
#Goswin Von Brederlow has already pointed out what is wrong, I will add a visual representation of what you are doing. Can you spot the problem?
EDIT: You can look in the comments for a better solution in terms of time and space (and also for a worse one).
After the while you should traverse the linked list. Since you don't have a "prev" (no double linked list) you need to traverse it multiple times to reverse it. I prepared a visualization of the algo, which uses a copy from left to right. And a support node for the prev node at each iteration. It uses idx and oidx to keep track of the position in the original and copied list.
And here are the steps of the iteration:

twist a doubly linked list

I have a Chain class that is made of a doubly linked list.
I want to twist two Chains so that every node at even positions will swap with each other. The Chain starts at position 1.
For example, say
this = {1,2,3,4}; //default chain
aChain = {5,6,7,8};
twist(aChain);
Now this would be {1,6,3,8}
and aChain would be {5,2,7,4}
Current Update:
void Chain::twist(Chain & other){
Node* firstOdd1 = this -> head_;
Node* firstOdd2 = other -> head_;
Node* firstEven1 = firstOdd1 -> next;
Node* firstEven2 = firstOdd2 -> next;
for(int i = 0; i < size(); i++){
firstOdd1 -> next = firstEven2;
firstOdd2 -> next = firstEven1;
firstEven1 -> prev = firstOdd2;
firstEven2 -> prev = firstOdd1;
if(firstEven1 -> next != NULL && firstEven2 -> next != NULL){
//updating my pointers for the next iteration
firstOdd1 = firstEven1 -> next;
firstOdd2 = firstEven2 -> next;
firstEven1 = firstOdd1 -> next;
firstEven2 = firstOdd2 -> next;}
else break;
}
}
As you see, I declared 4 pointers so that I don't lose any nodes during my assignments. I also have tail pointers that I need to assign to the last Nodes of both lists after the loop I suppose (if last Nodes are swapped). There's a size() function in the class that return the size of the chain.
This is what I wrote for the iteration step just now.
I left this as a comment, but I might as well make it an answer:
The algorithm is simple: swap the values at every even node in the chain.
No need to start worrying about tails and whatnot, just follow that pattern until you can no longer do it (i.e. you run out of even nodes), then stop and voila, problem solved!
You can clearly see it for the case you submitted:
{1,2,3,4};
{5,6,7,8};
==========
TWISTER
==========
| | |
v v v
{1,6,3,8};
{5,2,7,4};
Another example:
{1,2,3};
{5,6,7,8,9};
==========
TWISTER
==========
| | |
v v v
{1,6,3};
{5,2,7,8,9};
Another one!
{};
{5,6,7,8,9};
==========
TWISTER
==========
| | |
v v v
{};
{5,6,7,8,9};
ONE MORE TIME!
{1};
{5};
==========
TWISTER
==========
| | |
v v v
{1};
{5};
Maybe to help you, create a function which when called with a given node, tells you if it is possible to move it to the next even position.
bool can_move_to_even(Node* node) const {
if (node != nullptr) {
return node->next != nullptr && node->next->next != nullptr
&& node->next != this->_tail && node->next->next != this->_tail;
}
return false;
}
The checks for this->_tail are only for if your this->_tail is not to be considered part of the list, but if it is, then you can safely remove those.
Now what you can do is that if you pass in an even node, it will tell you if that node can reach the next even one or not. Once this function returns false for any of the chains you are twisting, that is when you know it is time to stop.
Be careful of nulls.

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.

Reversing a linked list between two nodes

I'm working on some homework for a CS class, and struggling a bit with a function that's meant to reverse a doubly linked list between two given nodes. I'm pretty confused about what I'm doing wrong, and I've searched google and SO and I can't find anything that helps me out.
I have a doubly linked list, and I'm essentially using this function as a helper function to reverse it between two nodes that are given as the parameters of the function.
Below is the code for the template, commented so you know my thought process
template <class T>
void List<T>::reverse( ListNode * & startPoint, ListNode * & endPoint )
{
//make sure that none of the pointers are null and that the start and
//end points aren't the same
if(startPoint == NULL || endPoint == NULL || startPoint == endPoint)
return;
//Make two nodes denoting everything happening before the
//start and everything after the end
ListNode *before = NULL;
ListNode *after = NULL;
if(startPoint->prev != NULL)
before = startPoint->prev;
if(endPoint->next != NULL)
after = endPoint->next;
ListNode *temp = startPoint;
ListNode *temp2;
//run a loop actually reversing the list. I have identified
//that this is where the problem is happening (obviously)
//for some reason the prev pointer for every node is being set to null
//so if I had a linked list with 1 2 3 4 5
//after running this it's just 5
while(temp!=endPoint && temp!=NULL){
temp2 = temp->next;
if(temp->prev!=NULL);
temp->next = temp->prev;
if(temp2!=NULL)
temp->prev = temp2;
temp = temp2;
}
//switch around the end and start pointers
endPoint = startPoint;
startPoint = temp;
//make sure it's integrated into the rest of the linked list
if(before != NULL){
before->next = startPoint;
startPoint->prev = before;
}
if(after != NULL){
after->prev = endPoint;
endPoint->next = after;
}
}
So, any ideas?
I've understood where the problem is happening, and what it is, but I haven't understood why it's happening, and how to fix it.
Also, feel free to let me know if you think I'm doing something redundant or unnecessary, I have a tendency to do that sometimes.
EDIT: This is an inclusive function, so if you called it on a linked list {1, 2, 3, 4, 5, 6} with pointers pointing to nodes with value 2 and 5, then the linked list would be changed to {1, 5, 4, 3, 2, 6}
The problem is with the ends of the sublist.
You haven't given a complete example (which would have helped), but suppose we start with the list {1, 2, 3, 4, 5}, and we attempt reverse(s, e), where s and e are pointers that point to 2 and 4. (So our desired result is {1, 4, 3, 2, 5}.)
This is where my skill at ASCII art fails, but the 'next' and 'prev' pointers look like this:
1-->2-->3-->4-->5
1<--2<--3<--4<--5
When control leaves the while loop, they look like this:
1<->2<--3 4-->5
1 2-->3<->4<--5
which is almost what we intended, but the process stopped one node to soon (the 4 has not been reversed). After it is "integrated into the rest of the list", they look like this:
________ ___
/ / \ \
1 2<--3 >4-->5
1 2-->3-->4 5
\___\_____/___/
Not very clear, but if you start at the beginning of the list and move forward, it goes {1, 4, 5}, and if you move backward from the end it goes {5, 2, 3, 4, 1}. You have broken the doubly-linked condition that if a.next points to b, then b.prev points to a, and vise-versa.
My advice (apart from drawing more arrows with pencil and paper) is to remove the sublist from the list, reverse it, then splice it back in; trying to reverse it in place is confusing.

Moving around pointers in a linked list

Question: Given a linked list with three pointers: first points to the first node, second to the third and third to the last node. Return a single pointer to the same list so that the 5th is the first and the the first is the last.
This was a question given to us in class, i'm having trouble understanding the question, but here is my attempted solution.
//List is the first pointer
//p is the second pointer (pointing to the third node)
//q is the last pointer (pointing to the last node)
R = p -> next //R, a name to a pointer i gave that is between p and q
p -> next = R -> next // don't even know what this means but wrote it down anyways
after this I am stuck, any help is appreciated but I would appreciate the full solution.
I would further appreciate a solution that utilizes STL
It can be done like this:
list *tmp, *tmp2, *pf, p3, pl; //pf: first, p3: 3rd, pl: last;
tmp = p3->next->next; //pointer of the 4th element to the 5th;
p3->next->next = tmp->next; //4th element now pointing to the 6th (since 5th moves to the beggining);
pl->next = pf; //make the first the last;
tmp2 = pf->next; //save the pointer to the 2nd;
pf->next = NULL; //pf is now last (-> pf->next has to be NULL);
tmp->next = tmp2; //old 5th now pointing to the 2nd (as it should be the first);
pf = tmp; //make the 5th the first -> this is what you want to return;
What is basically done here: You take out the 5th element (its pointer) out and therefore you have to connect 4 with 6. Now you put the first at the end. This is pretty easy since last->next is NULL anyway. The last thing you have to do now is making the 5th the 1st. For that you need to make it point to the 2nd. And that's it. As far as I understood you should wrap this also in a function which returns first then.