1.write A Program To Reverse The Linked List. (Both Iterative and Recursive)
1.write A Program To Reverse The Linked List. (Both Iterative and Recursive)
1.Write a Program to reverse the Linked List. (Both Iterative and recursive)
ITERATIVE:
LOGIC:
Initialize three pointers prev as NULL, curr as head and next as NULL.
Iterate through the linked list. In a loop, do the following.
next = curr->next
curr->next = prev
prev = curr
curr = next
CODE:
void reverse()
{ // Initialize current, previous and
// next pointers
Node* current = head;
Node *prev = NULL, *next = NULL;
RECURSIVE :
Divide the list in two parts - first node and
rest of the linked list.
2) Call reverse for the rest of the linked list.
3) Link rest to first.
4) Fix head pointer
CODE:
Node* reverse(Node* head)
{
if (head == NULL || head->next == NULL)
return head;
1.USING STACKS
Store the nodes(values and address) in the stack until all the values are entered.
Once all entries are done, Update the Head pointer to the last location(i.e the last value).
Start popping the nodes(value and address) and store them in the same order until the stack
is empty.
Update the next pointer of last Node in the stack by NULL.
while (!s.empty())
{ // Store the top value of
// stack in list
temp->next = s.top();
2.Using array
1.Create a linked list
2. Then, make a count(head) function to count the number of nodes.
4. and start a while(p->next!=NULL) loop and store all the node’s data into the array.
5. and then print the array from the last index to the first.
return head;
}
LOGIC:
Algorithm: reverse(head, k)
Reverse the first sub-list of size k. While reversing, keep track of the next node and previous
node. Let the pointer to the next node be next and pointer to the previous node be prev.
head->next = reverse(next, k) ( Recursively call for rest of the list and link the two sub-lists)
APPROACH 2
We have used a stack which will store the nodes of the given linked list. Firstly, push the k
elements of the linked list in the stack. Now pop elements one by one and keep track of the
previously popped node. Point the next pointer of prev node to top element of stack. Repeat
this process, until NULL is reached.
APPROACH : Traverse the list one by one and keep putting the node addresses in a Hash Table. At any
point, if NULL is reached then return false, and if the next of the current nodes points to any of the
previously stored nodes in Hash then return true.
while (h != NULL) {
// If this node is already present
// in hashmap it means there is a cycle
// (Because you we encountering the
// node for the second time).
if (s.find(h) != s.end())
return true;
h = h->next;
}
return false;
}
Time complexity: O(n).
Only one traversal of the loop is needed.
Auxiliary Space: O(n).
n is the space required to store the value in hashmap.
ALGORITHM
This solution requires modifications to the basic linked list data structure.
Have a visited flag with each node.
Traverse the linked list and keep marking visited nodes.
If you see a visited node again then there is a loop. This solution works in O(n) but requires
additional information with each node.
A variation of this solution that doesn’t require modification to basic data structure can be
implemented using a hash, just store the addresses of visited nodes in a hash and if you see
an address that already exists in hash then there is a loop.
CODE :
h = h->next;
}
return false;
}
Time complexity:O(n).
Only one traversal of the loop is needed.
Auxiliary Space:O(1).
No extra space is needed.
APPROACH:
Traverse linked list using two pointers.
If these pointers meet at the same node then there is a loop. If pointers do not meet
then linked list doesn’t have a loop
int detectLoop(Node* list)
Auxiliary Space:O(1).
There is no space required.
APPROACH: marking visited nodes without modifying the linked list data structure
In this method, a temporary node is created. The next pointer of each node that is traversed
is made to point to this temporary node. This way we are using the next pointer of a node as
a flag to indicate whether the node has been traversed or not. Every node is checked to see
if the next is pointing to a temporary node or not. In the case of the first node of the loop, the
second time we traverse it this condition will be true, hence we find that loop exists. If we
come across a node that points to null then the loop doesn’t exist.
return false;
}
APPROACH :
This is the simplest approach to the given problem, the only thing we have to do is to assign
a new value to each node in the linked list which is not in the range given.
Example suppose (1 <= Data on Node <= 10^3) then after visiting node assign the
data as -1 as it is out of the given range.
CODE :
// Function to detect first node of loop
// in a linked list that may contain loop
We do not need to count number of nodes in Loop. After detecting the loop, if we start slow
pointer from head and move both slow and fast pointers at same speed until fast don’t meet,
they would meet at the beginning of the loop.
/* If loop exists */
if (slow == fast)
{
slow = head;
If a loop is found, initialize a slow pointer to head, let fast pointer be at its position.
Move both slow and fast pointers one node at a time.
The point at which they meet is the start of the loop.
Function to detect and remove loop
// in a linked list that may contain loop
Node* detectAndRemoveLoop(Node* head)
{
// If list is empty or has only one node
// without loop
if (head == NULL || head->next == NULL)
return NULL;
return slow;
}
so if we start moving both pointers again at the same speed such that one pointer (say slow) begins
from the head node of the linked list and other pointers (say fast) begins from the meeting point. When
the slow pointer reaches the beginning of the loop (has made m steps), the fast pointer would have
made also moved m steps as they are now moving the same pace. Since m+k is a multiple of n and fast
starts from k, they would meet at the beginning. Can they meet before also? No, because the slow
pointer enters the cycle first time after m steps.
Method 2:
this method, a temporary node is created. The next pointer of each node that is traversed is made to
point to this temporary node. This way we are using the next pointer of a node as a flag to indicate
whether the node has been traversed or not. Every node is checked to see if the next is pointing to a
temporary node or not. In the case of the first node of the loop, the second time we traverse it this
condition will be true, hence we return that node.
The code runs in O(n) time complexity and uses constant memory space.
return head;
}
We can also use the concept of hashing in order to detect the first node of the loop. The idea is simple
just iterate over the entire linked list and store node addresses in a set(C++ STL) one by one, while
adding the node address into the set check if it already contains that particular node address if not then
add node address to set if it is already present in the set then the current node is the first node of the
loop.
ListNode* detectCycle(ListNode* A)
{
// declaring map to store node address
unordered_set<ListNode*> uset;
ListNode *ptr = A;
ptr = ptr->next;
}
return NULL;
}
6.Remove Duplicates in a sorted Linked List.
APPROACH : Traverse the list from the head (or start) node. While traversing, compare each node with
its next node. If the data of the next node is the same as the current node then delete the next node.
Before we delete a node, we need to store the next pointer of the node .
Time Complexity: O(n) where n is the number of nodes in the given linked list.
/* The function removes duplicates
from a sorted list */
Using Map :
The idea is to push all the values in a map and printing its keys.
prev->next = temp;
prev = temp;
}
temp = temp->next;
}
Algorithm:
Traverse the list till last node. Use two pointers: one to store the address of last node and other for
address of second last node. After the end of loop do following operations.
Reverse given linked list. For example, 1-> 9-> 9 -> 9 is converted to 9-> 9 -> 9 ->1.
Start traversing linked list from leftmost node and add 1 to it. If there is a carry, move to the next
node. Keep moving to the next node while there is a carry.
traverse both lists and One by one pick nodes of both lists and add the values. If the sum is more than
10 then make carry as 1 and reduce the sum. If one list has more elements than the other then consider
the remaining values of this list as 0.
if (res == NULL)
res = temp;
if (carry > 0)
temp->next = newNode(carry);
Fill s3 by creating new nodes and setting the data of new nodes to the sum of
s1.top(), s2.top() and carry until list1 and list2 are empty .
set carry 1
else
set carry 0
Create a Node(say prev) that will contain the head of the sum List.
return prev
int carry = 0;
// Fill the third stack with the sum of first and second
// stack
while (!s1.empty()) {
int sum = carry + s1.top()->data;
Node* temp = newnode(sum % 10);
s3.push(temp);
if (sum > 9) {
carry = 1;
}
else {
carry = 0;
}
s1.pop();
}
while (!s2.empty()) {
int sum = carry + s2.top()->data;
Node* temp = newnode(sum % 10);
s3.push(temp);
if (sum > 9)
{
carry = 1;
}
else {
carry = 0;
}
s2.pop();
}
if (carry == 1) {
Node* temp = newnode(1);
s3.push(temp);
}
if (!s3.empty())
prev = s3.top();
while (!s3.empty()) {
Node* temp = s3.top();
s3.pop();
if (s3.size() == 0) {
temp->next = NULL;
}
else {
temp->next = s3.top();
}
}
return prev;
}
time Complexity: O(m+n) where m and n are number of nodes in first and second linked
lists respectively.
Only one traversal of the lists are needed.
push(lastPtrRef, a->data);
lastPtrRef = &((*lastPtrRef)->next);
a = a->next;
b = b->next;
}
else if (a->data < b->data)
a = a->next; /* advance the smaller list */
else
b = b->next;
}
return (result);
}
Time Complexity: O(m+n) where m and n are number of nodes in first and second
linked lists respectively.
Only one traversal of the lists are needed.
Recursive Solution.
Approach:
The recursive approach is very similar to the the above two approaches. Build a
recursive function that takes two nodes and returns a linked list node. Compare the
first element of both the lists.
If they are similar then call the recursive function with the next node of both the lists.
Create a node with the data of the current node and put the returned node from the
recursive function to the next pointer of the node created. Return the node created.
If the values are not equal then remove the smaller node of both the lists and call the
recursive function.
// base case
if (a == NULL || b == NULL)
return NULL;
Use 2 nested for loops. The outer loop will be for each node of the 1st list and inner loop will be for
the 2nd list. In the inner loop, check if any of the nodes of the 2nd list is the same as the current
node of the first linked list. The time complexity of this method will be O(M * N) where m and n are
the numbers of nodes in two lists.
Method 2
Get count of the nodes in the first list, let count be c1.
Get count of the nodes in the second list, let count be c2.
Now traverse the bigger list from the first node till d nodes so that from here onwards both the lists
have equal no of nodes .Then we can traverse both the lists in parallel till we come across a
common node. (Note that getting a common node is done by comparing the address of the nodes)
// If first is greater
if (c1 > c2) {
d = c1 - c2;
return _getIntesectionNode(d, head1, head2);
}
else {
d = c2 - c1;
return _getIntesectionNode(d, head2, head1);
}
}
return -1;
}
return count;
}
(Use Hashing)
Basically, we need to find a common node of two linked lists. So we hash all nodes of the first list
and then check the second list.
1) Create an empty hash set.
2) Traverse the first linked list and insert all nodes’ addresses in the hash set.
3) Traverse the second list. For every node check if it is present in the hash set. If we find a node in
the hash set, return the node.
13.Merge Sort For Linked lists.[Very Important]
mergeSort():
merge(head1, head2):
1. Take a pointer say merged to store the merged list in it and store a dummy node in it.
2. Take a pointer temp and assign merge to it.
3. If the data of head1 is less than the data of head2, then, store head1 in next of temp
& move head1 to the next of head1.
4. Else store head2 in next of temp & move head2 to the next of head2.
5. Move temp to the next of temp.
6. Repeat steps 3, 4 & 5 until head1 is not equal to null and head2 is not equal to null.
7. Now add any remaining nodes of the first or the second linked list to the merged
linked list.
8. Return the next of merged(that will ignore the dummy and return the head of the final
merged linked list)
Method 1:
Traverse the whole linked list and count the no. of nodes. Now traverse the list again till count/2 and
return the node at count/2.
Method 2:
Traverse linked list using two pointers. Move one pointer by one and the other pointers by two. When the
fast pointer reaches the end slow pointer will reach the middle of the linked list.
if (head!=NULL)
{
while (fast_ptr != NULL && fast_ptr->next != NULL)
{
fast_ptr = fast_ptr->next->next;
slow_ptr = slow_ptr->next;
}
cout << "The middle element is [" << slow_ptr->data << "]" << endl;
}
}
The idea is to store head of the linked list and traverse it. If we reach NULL, linked list is not circular. If
reach head again, linked list is circular.
// Next of head
struct Node *node = head->next;
APPROACH:
1) Store the mid and last pointers of the circular linked list using tortoise and hare algorithm.
2) Make the second half circular.
3) Make the first half circular.
4) Set head (or start) pointers of the two linked lists.
In the below implementation, if there are odd nodes in the given circular linked list then the first result list
has 1 more node than the second result list.
if(head == NULL)
return;
/* If there are odd nodes in the circular list then
fast_ptr->next becomes head and for even nodes
fast_ptr->next->next becomes head */
18.Write a Program to check whether the Singly Linked list is a palindrome or not. .
// Temp pointer
Node* slow= head;
// Declare a stack
stack <int> s;
// Move ahead
slow = slow->ptr;
}
// Move ahead
head=head->ptr;
}
return true;
}
When a number of nodes are even, the first and second half contain exactly half nodes. The challenging
thing in this method is to handle the case when the number of nodes is odd. We don’t want the middle
node as part of the lists as we are going to compare them for equality. For odd cases, we use a separate
variable ‘midnode’.
// initialize result
bool res = true;
if (head != NULL && head->next != NULL)
{
if (fast_ptr != NULL)
{
midnode = slow_ptr;
slow_ptr = slow_ptr->next;
}
// compare
res = compareLists(head, second_half);
if (midnode != NULL)
{
prev_of_slow_ptr->next = midnode;
midnode->next = second_half;
}
else
prev_of_slow_ptr->next = second_half;
}
return res;
}
The idea is to use function call stack as a container. Recursively traverse till the end of list.
When we return from last NULL, we will be at the last node. The last node to be compared
with first node of list.
In order to access first node of list, we need list head to be available in the last call of recursion. Hence,
we pass head also to the recursive function. If they both match we need to compare (2, n-2) nodes.
Again when recursion falls back to (n-2)nd node, we need reference to 2nd node from the head. We
advance the head pointer in the previous call, to refer to the next node in the list.
However, the trick is identifying a double-pointer. Passing a single pointer is as good as pass-by-value,
and we will pass the same pointer again and again. We need to pass the address of the head pointer for
reflecting the changes in parent recursive calls.
return isp1;
}
// A wrapper over isPalindromeUtil()
bool isPalindrome(struct node* head)
{
isPalindromeUtil(&head, head);
}
Algorithm
Traverse the list using curr to find the node to be deleted and before moving to curr
to the next node, every time set prev = curr.
If the node is found, check if it is the only node in the list. If yes, set head = NULL and
free(curr).
If the list has more than one node, check if it is the first node of the list. Condition to
check this( curr == head). If yes, then move prev until it reaches the last node. After
prev reaches the last node, set head = head -> next and prev -> next = head. Delete
curr.
If curr is not the first node, we check if it is the last node in the list. Condition to check
this is (curr -> next == head).
If curr is the last node. Set prev -> next = head and delete the node curr by free(curr).
If the node to be deleted is neither the first node nor the last node, then set prev ->
next = curr -> next and delete curr.
Node *last=*head,*d;
// If head is to be deleted
if((*head)->data==key)
{
Here is a simple method for reversing a Doubly Linked List. All we need to do is swap prev and next
pointers for all nodes, change prev of the head (or start) and change the head pointer in the end.
* Function to reverse a Doubly Linked List */
void reverse(Node **head_ref)
{
Node *temp = NULL;
Node *current = *head_ref;
/* Before changing the head, check for the cases like empty
list and list with only one node */
if(temp != NULL )
*head_ref = temp->prev;
}
Time Complexity: O(N), where N denotes the number of nodes in the doubly linked list.
Auxiliary Space: O(1)
We can also swap data instead of pointers to reverse the Doubly Linked List. Method used for reversing
array can be used to swap data. Swapping data can be costly compared to pointers if the size of the
data item(s) is more.
Method 2:
Steps:
1. Keep pushing the node’s data in the stack. -> O(n)
2. The keep popping the elements out and updating the Doubly Linked List
In this method, we traverse the linked list once and add elements to the stack, and
again traverse the whole for updating all the elements. The whole takes 2n time,
which is the time complexity of O(n)
Given a sorted doubly linked list of positive distinct elements, the task is to find pairs in a doubly-linked
list whose sum is equal to given value x, without using any extra space?
A simple approach for this problem is to one by one pick each node and find a second element whose
sum is equal to x in the remaining list by traversing in the forward direction. The time complexity for this
problem will be O(n^2), n is the total number of nodes in the doubly linked list.
● Initialize two pointer variables to find the candidate elements in the sorted doubly
linked list. Initialize first with the start of the doubly linked list i.e; first=head and
initialize second with the last node of the doubly linked list i.e; second=last_node.
● We initialize first and second pointers as first and last nodes. Here we don’t have
random access, so to find the second pointer, we traverse the list to initialize the
second.
● If current sum of first and second is less than x, then we move first in forward
direction. If current sum of first and second element is greater than x, then we move
second in backward direction.
● Loop termination conditions are also different from arrays. The loop terminates when
two pointers cross each other (second->next = first), or they become the same (first
== second).
● The case when no pairs are present will be handled by the condition “first==second”
If linked list is not sorted, then we can sort the list as a first step. But in that case overall time complexity
would become O(n Log n). We can use Hashing in such cases if extra space is not a constraint.
22.Count triplets in a sorted DLL whose sum is equal to given value “X”.
// increment count
count++;
// pair found
if ((first->data + second->data) == value) {
// increment count
count++;
Sort the given doubly linked list using the insertion sort technique. While inserting each element in the
sorted part of the list, there will be at most k swaps to place the element to its correct position since it is
at most k steps away from its correct position.
Efficient Approach: We can sort the list using the MIN HEAP data structure. The approach has been
explained in Sort a nearly sorted (or K sorted) array. We only have to be careful while traversing the
input doubly linked list and adjusting the required next and previous links in the final sorted list.
if (newHead == NULL) {
newHead = pq.top();
newHead->prev = NULL;
else {
last->next = pq.top();
pq.top()->prev = last;
last = pq.top();
}
Create a recursive function, say reverse(head, k). This function receives the head or the first node of
each group of k nodes. It reverses those group of k nodes . After reversing the group of k nodes the
function checks whether next group of nodes exists in the list or not. If group exists then it makes a
recursive call to itself with the first node of the next group and makes the necessary adjustments with
the next and previous links of that group. Finally it returns the new head node of the reversed group.
Given a linked list where every node represents a linked list and contains two pointers of its type:
(i) Pointer to next node in the main list (we call it ‘right’ pointer in the code below)
(ii) Pointer to a linked list where this node is headed
The idea is to use the Merge() process of merge sort for linked lists. We use merge() to merge lists one
by one. We recursively merge() the current list with the already flattened list.
The down pointer is used to link nodes of the flattened list.
else
{
result = b;
result.down = merge(a, b.down);
}
result.right = null;
return result;
}
// now merge
root = merge(root, root.right);
Traverse the list and count the number of 0s, 1s, and 2s. Let the counts be n1, n2, and n3
respectively.
Traverse the list again, fill the first n1 nodes with 0, then n2 nodes with 1, and finally n3
nodes with 2.
int i = 0;
ptr = head;
● Create the copy of node 1 and insert it between node 1 & node 2 in the original
Linked List, create a copy of 2 and insert it between 2 & 3. Continue in this fashion,
add the copy of N after the Nth node
● This works because original->next is nothing but a copy of the original and
Original->random->next is nothing but a copy of the random.
● Now restore the original and copy linked lists in this fashion in a single loop.
original->next = original->next->next;
copy->next = copy->next->next;
// Inserting node
curr->next = new Node(curr->data);
curr->next->next = temp;
curr = temp;
}
curr = start;
copy->next = copy->next?copy->next->next:copy->next;
original = original->next;
copy = copy->next;
}
return temp;
}
Method 1 (Simple)
Approach:
A Simple Solution is to initialize the result as the first list. Now traverse all lists starting from
the second list. Insert every node of the currently traversed list into result in a sorted way.
// if last node
if (head_0->next == NULL) {
arr[i] = head_i->next;
head_i->next = NULL;
head_0->next = head_i;
head_0->next->next = NULL;
break;
}
}
}
}
return arr[0];
}
● Time complexity: O(nk2)
● Auxiliary Space: O(1).
As no extra space is required
in this post, Divide and Conquer approach is discussed. This approach doesn’t require
extra space for heap and works in O(nk Log k)
It is known that merging of two linked lists can be done in O(n) time and O(n) space.
1. The idea is to pair up K lists and merge each pair in linear time using O(n) space.
2. After the first cycle, K/2 lists are left each of size 2*N. After the second cycle, K/4 lists
are left each of size 4*N and so on.
3. Repeat the procedure until we have only one list left.
/* Base cases */
if (a == NULL)
return (b);
else if (b == NULL)
return (a);
return result;
}
return arr[0];
}
first_ptr = first;
while (first_ptr) {
first_ptr = first_ptr->next;
result_ptr2 = result_ptr2->next;
}
result_ptr1 = result_ptr1->next;
second_ptr = second_ptr->next;
}
Method 1 (Simple)
Use two loops. In the outer loop, pick nodes of the linked list one by one. In the inner loop, check if there
exists a node whose value is greater than the picked node. If there exists a node whose value is greater,
then delete the picked node.
Time Complexity: O(n^2)
Method 2 (Use Reverse)
/* Initialize max */
struct Node* maxnode = head;
struct Node* temp;
PROBLEM : Given a Linked List of integers, write a function to modify the linked list such that
all even numbers appear before all the odd numbers in the modified linked list. Also, keep the
order of even and odd numbers same.
The idea is to get pointer to the last node of list. And then traverse the list starting from the head node
and move the odd valued nodes from their current position to end of the list.
Algorithm:
…1) Get a pointer to the last node.
…2) Move all the odd nodes to the end.
……..a) Consider all odd nodes before the first even node and move them to end.
……..b) Change the head pointer to point to the first even node.
……..b) Consider all odd nodes after the first even node and move them to the end.
// 10->8->17->17->15
/* Do following steps only if
there is any even node */
if (curr->data%2 == 0)
{
/* Change the head pointer to
point to first even node */
*head_ref = curr;
METHOD 2 :
The idea is to split the linked list into two: one containing all even nodes and other containing all odd
nodes. And finally, attach the odd node linked list after the even node linked list.
To split the Linked List, traverse the original Linked List and move all odd nodes to a separate Linked
List of all odd nodes. At the end of the loop, the original list will have all the even nodes and the odd
node list will have all the odd nodes. To keep the ordering of all nodes the same, we must insert all the
odd nodes at the end of the odd node list. And to do that in constant time, we must keep track of the last
pointer in the odd node list.
while(currNode != NULL)
{
int val = currNode -> data;
Function to get the nth node from the last of a linked list*/
temp = head;
return;
int count = 0;
if(head != NULL)
{
while( count < n )
{
if(ref_ptr == NULL)
{
printf("%d is greater than the no. of "
"nodes in list", n);
return;
}
ref_ptr = ref_ptr->next;
count++;
} /* End of while*/
if(ref_ptr == NULL)
{
head = head->next;
if(head != NULL)
printf("Node no. %d from last is %d ", n, main_ptr->data);
}
else
{
while(ref_ptr != NULL)
{
main_ptr = main_ptr->next;
ref_ptr = ref_ptr->next;
}
printf("Node no. %d from last is %d ", n, main_ptr->data);
}
}
}
Time Complexity: O(n) where n is the length of linked list.
The idea is to use a DLL (Doubly Linked List) to efficiently get the first non-repeating character from a
stream. The DLL contains all non-repeating characters in order, i.eThe head of the DLL contains the first
non-repeating character, the second node contains the second non-repeating and so on.
We also maintain two arrays: one array is to maintain characters that are already visited two
or more times, we call it repeated[],
The other array is an array of pointers to linked list nodes, we call it inDLL[]. The size of both
arrays is equal to alphabet size which is typically 256.
1. Create an empty DLL. Also create two arrays inDLL[] and repeated[] of size 256.
inDLL is an array of pointers to DLL nodes. repeated[] is a boolean array, repeated[x]
is true if x is repeated two or more times, otherwise false. inDLL[x] contains a pointer
to a DLL node if character x is present in DLL, otherwise NULL.
Note that appending a new node to DLL is O(1) operation if we maintain tail pointer.
Removing a node from DLL is also O(1). So both operations, addition of new character and
finding first non-repeating character take O(1) time.
temp->a = x;
if (*head_ref == NULL)
{
*head_ref = *tail_ref = temp;
return;
}
(*tail_ref)->next = temp;
temp->prev = *tail_ref;
*tail_ref = temp;
}
void removeNode(struct node** head_ref, struct node** tail_ref, struct node* temp)
{
if (*head_ref == NULL)
return;
if (*head_ref == temp)
*head_ref = (*head_ref)->next;
if (*tail_ref == temp)
*tail_ref = (*tail_ref)->prev;
if (temp->next != NULL)
temp->next->prev = temp->prev;
if (temp->prev != NULL)
temp->prev->next = temp->next;
delete (temp);
}
void findFirstNonRepeating()
{
// inDLL[x] contains pointer to
// a DLL node if x is present
// in DLL. If x is not present, then inDLL[x] is NULL
bool repeated[MAX_CHAR];