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.
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 new to linked lists and need help understanding how know how to merge two linked lists together. Everything in my program works but the function to merge the two lists together in ascending order.
head and first are pointers to the start of two separate linked lists.
void linkedListType::AscendMerge()
{
nodeType * c1;
nodeType * c2;
nodeType * p1;
nodeType * p2;
c1 = first;
c2 = head;
p1 = first;
p2 = head;
while (c1->link&&c2->link != NULL)
{
if (c1->info <= c2->info)
{
c1->link->link = c2->link;
}
if (c2->info < c1->info)
{
c1->link = c2->link;
}
cout << c1->info << " ";
c1 = c1->link;
c2 = c2->link;
}
}
There are two problems with your implementation. One has to do with the algorithm itself, and the second one has to do with the way it is coded in C++.
The problem with the algorithm is that your code does not deal with the "tails" of the lists: your while loop calls it quits as soon as one of the lists runs out of items, leaving the remaining items of the second list "orphaned".
Fixing this part is straightforward: all you need to do is linking the remaining non-null list to the end of the result.
The coding problem has several parts to it: first, your implementation is not receiving the two lists to be merged as parameters: both c1 and p1 are assigned head, presumably merging a list with itself. Second, your while loop stops before reaching the end of the list: c1->link being NULL means that c1 is the final node; your code never examines its value. Finally, your code does not return the merged list. Your code does modify link values, but when the merge touches the head, the pointer is neither modified nor returned.
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.
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.
I am a bit confused about time complexity of Linked Lists. In this article here it states that insertion and deletion in a linked list is O(1). I wanted to know how this is possible ? Is it assumed that the forward and next pointers are known ? Wouldn't that be Double Linked List then ? I would appreciate it if someone could clarify this . And how the time complexity of insertion/deletion of single linked list is O(1) ?
Is it assumed that the forward and next pointers are known ?
In singly linked lists, for both insertion and deletion, you need a pointer to the element before the insertion/deletion point. Then everything works out.
For example:
# insert y after x in O(1)
def insert_after(x, y):
y.next = x.next
x.next = y
# delete the element after x in O(1)
def delete_after(x):
x.next = x.next.next
For many applications it is easily possible to carry the predecessor of the item you are currently looking at through your algorithm, to allow for dynamic insertion and deletion in constant time. And of course you can always insert and delete at the front of the list in O(1), which allows for a stack-like (LIFO) usage pattern.
Deleting an item when you just know the pointer to the item is generally not possible in O(1). EDIT: As codebeard demonstrates, we can insert and delete by just knowing a pointer to the insertion/deletion point. It involves copying the data from the successor, thus avoiding fixing up the next pointer of the predecessor.
Yes, it's assuming that you already know the place at which you want to insert the data.
Suppose you have some item p in the list, and you want to insert a new element new after p in the list:
new->next = p->next;
p->next = new;
Alternatively, suppose you want to insert new before p. This can still be done in O(1) time:
if (p == head) {
new->next = head;
head = new;
} else {
tmp = p->data;
p->data = new->data;
new->data = tmp;
new->next = p->next;
p->next = new;
}
As for deleting items in a conventional singly linked list, it's not strictly O(1)!
It is O(1) for deleting any element except the last element. If you are trying to delete the last element in a singly linked list, you need to know the element before it (which requires O(N) time assuming you didn't know it before).
To delete the item p:
free_if_necessary(p->data);
if (p->next) {
/* O(1) */
nextnext = p->next->next;
nextdata = p->next->data;
destroy_if_necessary(p->next);
p->data = nextdata;
p->next = nextnext;
} else if (p == head) {
destroy_if_necessary(p);
head = NULL;
} else {
/* O(n) */
prev = find_prev(head, p);
destroy_if_necessary(p);
prev->next = NULL;
}
Maybe this is relative to the delete and insert operation for array.
And there is a prerequisite that you know the postion where to insert or delete.
In array, when you want to insert or delete an element at positon pos, you should move the other elements after the position pos, so the complexity is O(N).
But in List, when you do the same operation, you needn't consider the other elements, so the complexity is O(1).