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.
Related
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:
I am trying to swap the first and last elements of a linked list, but I have not been able to find a solution. My logic, or pseudo code, is to:
set the second-to-last node's next to the first node.
set the first node's next to a nullptr.
set the last node's next to the first node.
My current code is:
void SingleList::swapFirstAndLast()
{
Node *current = first;
while (current->getNext()->getNext() != nullptr)
{
current = current->getNext();
}
// current is equal to the second to last node
//set last node to first node
current->getNext()->setNext(first);
//set first node to nullptr
first->setNext(nullptr);
//set second to last to first node
current->setNext(first);
// set the first equal to the last node
first = current->getNext();
}
And my current output is:
Swap first and last nodes:
List before : 200 50 300 25
---------------------------
List after : 200
I'm not necessarily looking for a direct code answer, but any tips or advice on what I am missing here would be much appreciated.
Your logic has a flaw in its third point.
set the last node next to the first node
It should be.
set the old last node as the new first node.
Lets walk through your pseudo code. I assume first is a global pointer that points to the first node of your list.
|200|50|300|25|
^
first
after the while run the current pointer now points to the node with a value of 300
|200|50|300|25|
^ ^
first current
then we change the node with value 25 to point to first which leads to this
|50|300|25|200|
^ ^
current first
after that we close the list at first by pointing it to null, And set first as next of current
|50|300|200|
^ ^
current first
Now the error can be seen the reference to 25 is now lost.
After that we change the global first pointer to point to the next node of current which should be the node with value 25 but is not since it was replaced with the original first node.
To fix this you should change the end of your function like this.
Node * oldLast = current->getNext();
//set second to last to first node
current->setNext(first);
// set the first equal to the last node
first = oldLast;
I try to swap two nodes in a linked list as follows:
void swapTwo(course*& first, course*& second)
{
auto temp = first;
first = second;
second = temp;
second->next = first->next; // error right here due to self-referencing
first->next = second;
}
I got an error because second->next is already self-referencing. Is there an elegant solution to this? I can create 2 courses elements and re-construct first and second, but that seems so brute. Thanks!
You need to take multiple scenarios into account.
When the two aren't adjacent, nor is any of them the head or the tail
When they're adjacent
When either is the head or the tail
When one is the head while the other is the tail
When they're the only two in the linked list.
void NodeList::sortNodeAscending()
{
Node* swap = NULL;
Node* saveLink = NULL;
for(Node* firstPointer = head; firstPointer;firstPointer = firstPointer->next)
for(Node* secondPointer = firstPointer->next; secondPointer;secondPointer = secondPointer->next)
{
if((secondPointer->studentId)<(firstPointer->studentId))
{
swap =firstPointer;
saveLink = secondPointer->next;
firstPointer = secondPointer;
secondPointer = swap;
firstPointer->next = secondPointer;
secondPointer->next = saveLink;
}
}
}
This is my code for sorting but the problem that i have is after sorting, all the values are correct but the head is not changed or sorted.
Output:
{ 5, 0, 1, 2, 3, 4, 12, 15}
All the elements are sorted except the first node.
Note: I have already checked the question in the link below and it is different from my question. Sorting a Singly Linked List With Pointers
You are not updating head to point to the new start of the list.
At the end of the first iteration of the outer loop, firstPointer will point to the smallest element and can be updated to the new head.
Sorting of list is not as easy as it appears in your code:
[prev1] [first] [next1] ... [prev2] [second] [next2]
should look like this upon swapping first with second:
[prev1] [second] [next1] ... [prev2] [first] [next2]
How to do that:
Store next1 or next2, and keep track of prev1 and prev2 all the time as you can't look back in singly linked list.
first->next = next2 and second->next = next1
prev1->next = second and prev2->next = first
During all this, you need to take special care for list's head.
As pointed out by Kenny Ostrom, even if the head issues are fixed, if the initial sequence of student id's is 5,3,1,4,2, then the sort ends up with 5,1,3, not sorted and losing two values.
The code is swapping firstPointer and secondPointer, which are used as the inner and outer loop variables. This creates a problem.
When swapping nodes in a linked list, the nodes may be adjacent (three next pointers rotated) or they may be non-adjacent (two pairs of next pointers swapped). To handle both cases with the same code, first swap whatever points to the two nodes to be swapped first (like swap prev1->next with prev2->next), then swap the two node's next pointers (like swap curr1->next with curr2->next).
Trying to use bubble sort or any swapping sort to sort a linked list is complicated because you need to keep track of two previous pointers to nodes as well as two current pointers to nodes.
It would be simpler to start off with an empty "sorted" list, then remove one node at a time from the original list, and insert the node into it's proper location into the "sorted" list. For this method, start off with Node * sorted = NULL; Once all nodes have been removed from the original list and inserted in order into "sorted", then set head = sorted, so that head points to the sorted list.
A much faster method to sort a linked list uses a small (25 to 32) array of pointers to nodes combined with a bottom up merge sort, but that is more than what is needed in this case.
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 )