Why do I need to make 'head' equal to 'prev' to finish reversing a Linked List? - data-structures

sorry for the awkward question title. I don't really know how to explain without a code example. I have implemented a Linked List using generics, and I am trying to reverse it.
public Node<T> reverse() {
Node<T> prev = null;
while (head != null) {
Node<T> next = head.next;
head.next = prev;
prev = head;
head = next;
System.out.println("head: " + head.next + "\nprev: " + prev.next);
}
head = prev;
return prev;
}
head = prev;
My question is, why is this required?
My LinkedList outputs:
[output]
But without the head = prev; line it simply outputs blank []. Is this something to do with generics?

No, It has nothing to do with generics, Looking at your reverse method, initially, there are three nodes prev pointing to null, head pointing to start of the linked list, and next pointing to head's next node. At each step you are moving each node in forward direction until it is reversed, so after completion, your prev node will point to the tail of the linked list which is in fact the start of the reversed linked list, and both head and next pointing to null. So head = prev is needed to make the head point to the starting node of the reversed linked list.

*TLDR; Because at end of while loop, 'head' points to null, not the reversed list.
--
Let’s understand your code by an example:
List: 3 -> 6 -> 9 -> null
head points to 3.
// 1
Node<T> prev = null;
while(head != null) // true
Node<T> next = head.next; // next -> 6, as head.next points to Node with element 6
head.next = prev; // head->next = null, earlier it pointed to Node with element 6, prev is null
prev = head;
head = next;
Current state:
null <- 3 6 -> 9 -> null
Now, prev points to 3, head points to 6.
// 2
while(head != null) // true
Node<T> next = head.next; // next -> 9, as head.next points to Node with element 9
head.next = prev; // head->next =3, earlier it pointed to Node with element 9, prev is 3
prev = head;
head = next;
Current state:
null <- 3 <- 6 9 -> null
Now, prev points to 6, head points to 9.
// 3
while(head != null) // true
Node<T> next = head.next; // next -> null, as head.next points to null
head.next = prev; // head->next =6, earlier it pointed to null, prev is 6
prev = head;
head = next;
Current state:
null <- 3 <- 6 <- 9
Now, prev points to 9, head points to null.
// 4
while(head != null) // false
Now, head points to null and you need to return reversed linked list.
head = prev; // prev points to the node with element 9.
// null <- 3 <- 6 <- 9 <- prev (or head) as head and prev are equal.
return prev; // will return the reversed linked list.
return head; // will return the reversed linked list as both prev and head are equal.

Related

Linked List - Keeping track of each node

I found an algorithm to loop through a sorted linked list and remove the duplicate. I wrote it, it works.
Still, I don't understand how can this work. In the end of the loop, to move forward into the while loop, we do this :
currentNode = nextNode
How can this not erase the current node ? Why does the linked list is still here ? It feels every node is erased each time by the next, isn't it ?
class LinkedList {
constructor(value) {
this.value = value;
this.next = null;
}
}
function removeDuplicatesFromLinkedList(linkedList) {
let currentNode = linkedList;
while(currentNode !== null){
let nextNode = currentNode.next;
while(nextNode !== null && nextNode.value === currentNode.value){
nextNode = nextNode.next;
}
currentNode.next = nextNode
currentNode= nextNode
}
currentNode = linkedList;
return linkedList;
}
exports.LinkedList = LinkedList;
exports.removeDuplicatesFromLinkedList = removeDuplicatesFromLinkedList;
In fact, linkedList is never overwritten, so the initial list isn't damaged (because when removing duplicates, the first one is kept, only the following are removed).
Then, currNode is just the current pointer, to the current node. Assign a new value to it don't delete the previous node, since it's still referenced through the list head linkedList.
What is really missing is the free instruction on deleted node - this algo rely on a garbage collector to work without a memory leak.
Let's do this by an example:
2 -> 3 -> 3 -> 4
Initially currentNode == 2. In the first iteration of the loop nextNode == 3, which is the next node to current node. The inner while loop doesn't run since currentNode.value isn't equal to nextNode.value. So we hit:
currentNode.next = nextNode
currentNode= nextNode
This sets the next node of currentNode to NextNode. So, nothing changes. Then we move current node one forward: currentNode = nextNode
In the next iteration though, nextNode == 3, while currentNode == 3 too. Now the inner while loop runs one iteration and moves nextNode to 4 and breaks since they aren't equal anymore. Then, currentNode.next is set to nextNode, which was 4, and after nextNode is assigned to currentNode.
Since these are all pointers to nodes, nothing is being erased. Just the duplicate values are removed from the chain of linked nodes.

Find the maximum sum of first and last element of a linked list

Given a singly linked list where each element contains a number and a pointer to the head of the list. Sum the first and last data and remove these nodes. Then sum the first and last data of the resulting linked list and remove these two nodes.
Keep doing this till the list becomes empty.
we have to find the maximum sum obtained from the resulting sum in O(1) space complexity.
The list is a singly linked list with even nodes.
My Thoughts:
One approach is to move the pointer to the last element at each iteration, remove the nodes, and keep a maxSum variable. This probably won't be an efficient solution.
If I understood correctly, a node in this linked list has two pointers: a pointer to the next node and one to the first node in the list.
There are several ways to solve this. Here is one:
Walk through the list and change the head pointer in each node to reference the previous node: this will give you a doubly linked list. Retain a pointer to the last node.
Now you can do a traversal in tandem starting at both ends of the list and walking towards each other.
Deleting nodes during that traversal is not really required. You could even restore the list to what it was originally in the second step.
It is even possible to do this without this extra head pointer in each node. In that case reverse the second half of the list.
Here is an implementation of the first idea, in JavaScript:
class Node {
constructor(data, head) {
this.data = data;
this.head = head || this; // default is node itself
this.next = null;
}
}
function createList(...values) {
if (!values) return null;
let head = new Node(values.shift()); // First value
let tail = head;
for (let value of values) { // Remaining values
tail.next = new Node(value, head);
tail = tail.next;
}
return tail.head;
}
function maxPairSum(head) {
if (!head) return -Infinity;
// Make doubly linked list, (ab)using node's head member
let tail;
for (tail = head; tail.next; tail = tail.next) {
tail.next.head = tail; // Next gets reference to previous
}
// Tandem walk, towards center
let maxSum = -Infinity;
for (let curr = head; curr != tail && curr != tail.next; curr = curr.next) {
maxSum = Math.max(maxSum, curr.data + tail.data);
tail = tail.head; // Is actually a reference to previous
}
// Restore head references (optional)
for (let curr = head; curr; curr = curr.next) {
curr.head = head;
}
return maxSum;
}
// Example run
let head = createList(2, 5, 1, 5, 4, 6);
let maxSum = maxPairSum(head);
console.log(maxSum); // 9
... And if you want to really remove the list, just clear the head reference. In JavaScript the garbage collector will free the unreachable memory; in some other languages (like C) you'll need to explicitly free the memory occupied by each node, before clearing the reference to the head node.
private static int max = 0, count = 0;
private static LinkedList top;
static int maximumPagesRec(LinkedList tail) {
if(tail.next==null)
max = max<top.data + tail.data ?top.data + tail.data: max;
else if(tail == top && count++ !=0){
max = max<top.data ?tail.data: max;
}
else if(top.next == tail && count++!=1)
max = max<top.data + tail.data ?top.data + tail.data: max;
else {
maximumPagesRec(tail.next);
}
top = top.next;
return max;
}
static int maximumPages(LinkedList head)
{ top = head;
return maximumPagesRec(head);
}
how about pushing all linked list value element to a stack, take 1->2->3->4 for example, and the stack will be 1234.
after that, we sum one by one and delete each linked list, store maximum value we got.

Deleting nodes greater than specified value from linked list

Given an integer value and a pointer to the head of the linked list, how to delete all the nodes from the list that are greater than the specified value?
e.g.
List : 10->34->11->19->26->55->17
value: 19
output: 10->11->17 (All the nodes greater than 19 needs to be removed)
(Edge case)
List : 10->3->17->5->2->14->7
value: 9
output: 3->5->2->7 (All the nodes greater than 9 needs to be removed)
I am not looking for the exact code but just an algorithm to solve this!
private static Node removeNodes(Node start, int x) {
if(start == null) return start;
if(start.data > x && start.next == null) return null;
//find first head node
Node cur = start;
Node prev = null;
//4,5,3,2,1,6 --- where x = 2
while(cur != null && cur.data > x) {
prev = cur;
cur = cur.next;
}
if(prev != null) prev.next = null;
Node newHead = cur;
while(cur.next != null) {
if(cur.next.data > x) {
cur.next = cur.next.next;
} else {
cur = cur.next;
}
}
return newHead;
}
first assign a temporary node to the start node
Then you have three cases in linked list..
if the desired node at the first position then make start to be equal start->next and delete temp node
if it is in the middle make another node to be stopped right before temp and make the next of that node to be equal the next of temp and then delete temp
if it is at last position make the next of the node before it to be equal to nullptr and that is it.
It can be solved using two pointers, previous and current,I guess this solution work.
public static ListNode removeNode(ListNode head,int value){
//removing every element whose Node value is greter than given value
if(head==null) { return head;}
ListNode current=head;
ListNode previous=new ListNode(0);
previous.next=current;
while(current!=null){
//System.out.println("current value; "+current.val);
if(current.val>=value){
if(current.next==null){
current=null;
}
else {
current=current.next;}
previous.next=current;
}
else {
previous=previous.next;
current=current.next;
}
}
return head;
}
Consider the picture here .Suppose we have to delete the node which is greater than 8 and we have Head Pointer pointing to head of the list.First we will take two pointers Prev and temp both points to head initially.Then through the pointer we will traverse the list and keep track the current and prev pointers in temp and Prev.If current number is greater than 8 Prev will point to the next node pointed by temp and temp node will be deleted.By traversing all the node and following this rule you can delete the specified node of the list....
I hope you got the point........

How to understand head->next->next = head; for reverse single list by Recursion?

A signle link list, i want revese it by recursion. but i don't understand the meaning of this line head->next->next = head;.
why there need head->next->next?
struct Node{
int data;
Node* next;
};
Here is the implement code:
Node* reverseByRecursion(Node *head)
{
if(head == NULL || head->next == NULL)
return head;
Node *newHead = reverseByRecursion(head->next);
head->next->next = head;
head->next = NULL;
return newHead;
}
Let me work with this list.
reverseByRecursion(node1) is called.
Neither node1 nor node1->next is NULL, so newHead = reverseByRecursion(head2); is called.
Neither node2 nor node2->next is NULL, so newHead = reverseByRecursion(head3); is called.
head3->next is NULL, so head3 is returned from reverseByRecursion(head2).
head = node2 and head->next = node3, so head->next->next = head; will set node3->next to node2.
head->next = NULL; will set node2->next to NULL. (image 2)
newHead, which is node3, is returned from reverseByRecursion(head2).
head = node1 and head->next = node2, so head->next->next = head; will set node2->next to node1.
head->next = NULL; will set node1->next to NULL. (image 3)
newHead, which is node3, is returned from reverseByRecursion(node1).
Now the list is reversed with having node3 as the head.
image 2
image 3
try to understand it this way, .next actually meant to change the arrow pointing to the next value. So
head.next.next = head
means adding an arrow from the next next position and point it back to head
Hope this is more intuitive to understand
Your base case says that if there are no more elements, then the current node becomes the head of the list.
The head->next->next = head line means that the next node is being reused with its pointer pointing backward (in the opposite direction as before). Since the node used to be the NEXT node after the current node, it becomes the PREVIOUS node before the current head, and its next pointer therefore ought to point to the current node ("head").

Reverse a doubly linked list

Here's my simple linked list program that creates a doubly linked list, and it works.
#include <iostream>
using namespace std;
typedef struct node {
int data;
node *next;
node *prev;
}node;
void printList(node *temp);
int main()
{
node *head;
head = new node;
head->prev = NULL;
node *next = head;
node *prev = head;
node *temp = head;
node *current = head;
//creates 100 nodes, last one points to next
for(int x = 0; x<100; x++)
{
temp->data = x;
current = temp;
temp = new node;
current->next = temp;
temp->prev = current;
temp->next = NULL;
}
//=========================================
printList(head);
//=========== set everything to head ===========
current = head;
prev = head;
//============= reverses linked list ============
while(current->next != NULL)
{
next = current->next; //moves next pointer to next node
current->prev = next; //points current's previous to next node
current = next; //set current pointer to next node
current->next = prev; //set current's next to previous node
prev = current; //move prev node up to current
}
//================================================
printList(head);
cout<<"done";
return 0;
}
void printList(node *temp)
{
while(temp->next != NULL)
{
cout<<temp->data<<'\n';
temp = temp->next;
}
}
Once I add the reverse function though, it hangs. Actually, the function itself works, but in an IDE, when I LOOP it, it prints out all the values, then just hangs(sits there with blinking cursor) and does nothing.
Solution: Got it to work. This is what my function ended up being.
current = head; //set current pointer to head
prev = head; //set previous pointer to head
next = current->next; //moves next pointer to next node
current->next = NULL; //set the next of the header to NULL, because it will actually be the last
//node of reversed list.
current->prev = next; //set previous of the header to the next node.
while(next != NULL)
{
current = next;
next = current->next;
current->prev = next;
current->next = prev;
prev = current;
}
Your reverse algorithm is basically broken.
On the first pass through:
current = head; // Current is pointing at node 0, node0->next is 1 from before
prev = head; // Prev is pointing at node 0
next = current->next; // next is pointing at 1
current->prev = next; // node0->prev is pointing at 1
current = next; // current is pointing at 1
current->next = prev // node1->next is pointing at 0
then next pass
next = current->next // read up there ^^^ node1->next is pointing at 0
... so next goes back to to node 0.
That is not what you meant to do - it causes you to loop around nodes 1 and zero repeatedly, instead of progressing to node 2 and beyond...
Note that you could have easily debugged this if you put this code into the reverse loop:
cout<<"\nStarting iteration"
cout<<"\nNext is at" << next->data
cout<<"\nCurrent is at" << current->data
cout<<"\nCurrent->next is" << current->next->data
etc... doesn't take long to type, reveals all :)
(probably you would cut it down to do 3 instead of 100)
I just did the steps for 3 nodes manually (on paper) to deduce this answer...
Look this simple solution..
Node* Reverse(Node* head)
{
Node * curr=head;
Node * prev=NULL,* nxt=NULL;
while(curr!=NULL)
{
nxt=curr->next;
curr->next=prev;
curr->prev=nxt;
prev=curr;
curr=nxt;
}
return prev;
// Complete this function
// Do not write the main method.
}

Resources