Best Linked List Interview Questions for 2023 - IQCode
Introduction to Linked List
Linked List is a linear data structure that is similar to an array. The primary difference is that the elements are not stored in contiguous memory locations. Instead, a node in the linked list contains a data value and a pointer to the next node. In this article, we will understand the purpose of a Linked List, its advantages and disadvantages, representation, and a brief history.
Purpose of Linked List
Arrays are great for storing a fixed size of data, but when the size of data is unknown and can change dynamically, they are not suitable. Additionally, arrays cannot perform insertions and deletions efficiently. Here the linked list comes into the picture. Linked List behaves dynamically, and its size can change as per the requirement. It is frequently used to build linear data structures like stacks and queues. Linked List is much more convenient to insert and delete items as we don't have to move into elements in memory when compared to an array.
Advantages of Linked List
- Linked List is flexible, and it grows and shrinks dynamically during runtime. - No memory wastage in Linked List. - New nodes are efficiently added and deleted. - Linked List does not have a predetermined size.
Disadvantages of Linked List
- Linked List requires more memory. - Traversing a Linked List is slower compared to an array. - Reverse traversing is not possible in a singly linked list, but it is possible in a doubly-linked list.
Representation
In C, we represent a Node using a structure that contains data and a reference to the next node. In Java or C#, we can represent a Linked List as a class and Node as an inner class.
Brief History
Linked Lists are invented by Allen Newell, Cliff Shaw, and Herbert A. Simon of RAND Corporation in 1955-1956. The authors incorporated it into their Information Processing Language and utilized it to create early AI applications. Hans Peter Luhn recommended the use of Linked Lists in chained hash tables in an IBM memo in 1953.
Linked List Interview Questions for Freshers
How can we find the middle element of a singly Linked List without iterating the list more than once?
Converting a Binary Tree to a Doubly-Linked List
Code:
class Node:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
def convert_bt_to_dll(root):
if root is None:
return root
if root.left:
left_node = convert_bt_to_dll(root.left)
while left_node.right:
left_node = left_node.right
left_node.right = root
root.left = left_node
if root.right:
right_node = convert_bt_to_dll(root.right)
while right_node.left:
right_node = right_node.left
right_node.left = root
root.right = right_node
return root
Explanation:
This code uses recursion to traverse the binary tree. The function 'convert_bt_to_dll' takes the root of the binary tree as an input parameter and recursively converts the binary tree to a doubly-linked list. It first checks if the root is None. If it is, it returns the root. Then, it recursively calls the function on the left subtree and stores the result in 'left_node'. It then traverses to the rightmost node of 'left_node' to get the tail node of the doubly-linked list. It then sets the right node of 'left_node' to the current root node and sets the left node of the current root node to 'left_node'. It then recursively calls the function on the right subtree and stores the result in 'right_node'. It then traverses to the leftmost node of 'right_node' to get the head node of the doubly-linked list. It then sets the left node of 'right_node' to the current root node and sets the right node of the current root node to 'right_node'. It then returns the current root node.
Removing a Cycle from a Linked List in Python
To remove a cycle from a linked list in Python, we can use the Floyd's Cycle-Finding Algorithm also known as the "tortoise and hare" algorithm.
Code:
class Node:
def __init__(self, data):
self.data = data
self.next = None
def removeCycle(head):
if head == None or head.next == None:
return None
slow = head
fast = head
while True:
slow = slow.next
if fast.next != None:
fast = fast.next.next
else:
return None
if slow == None or fast == None:
return None
if slow == fast:
break
slow = head
while (slow.next != fast.next):
slow = slow.next
fast = fast.next
fast.next = None
return head
The Floyd’s Cycle-Finding Algorithm is used to detect a loop in a linked list. Once a loop is detected, we can use another algorithm to remove it. This algorithm uses two pointers, one running slowly with one node at a time while the other pointer runs twice as fast. If there is a loop in the linked list the fast pointer will eventually meet the slow pointer. We can then traverse the linked list starting from the head node with both pointers and their next. When they both meet, we can break the loop.
Finding Similar Elements in Two Linked Lists
Assuming there are no duplicates in the linked lists, we can use a simple approach to find the similar elements in them.
We can iterate over the elements of the first linked list and for each element, we can compare it with the elements of the second linked list. If a match is found, we can add that element to a new linked list.
Here's the implementation of this algorithm in Python:
class Node:
def __init__(self, data=None):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def append(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
else:
current_node = self.head
while current_node.next:
current_node = current_node.next
current_node.next = new_node
def print_list(self):
current_node = self.head
while current_node:
print(current_node.data, end=" ")
current_node = current_node.next
print("\n")
def find_similar_elements(list1, list2):
similar_list = LinkedList()
current_node = list1.head
while current_node:
if current_node.data in list2.__dict__.values():
similar_list.append(current_node.data)
current_node = current_node.next
return similar_list
We create a `Node` and `LinkedList` class. The `LinkedList` class has a `print_list` method to print the elements of the linked list. The `find_similar_elements` function takes in two linked lists as parameters and returns a new linked list of the similar elements between them.
We iterate over the elements of the first linked list `list1` and check if each element is present in the second linked list `list2`. If a match is found, we add that element to the `similar_list` linked list. Finally, we return the `similar_list` linked list.
Note that we have used the `__dict__.values()` method on `list2` to get a list of all the data elements of the list. This is because we have assumed that there are no duplicate elements in the linked list.
Why is Merge Sort a Better Option than Quicksort for Linked Lists?
When it comes to sorting data in a linked list, Merge Sort proves to be a better option as compared to Quicksort. This is because Merge Sort has a time complexity of O(n log n) which remains the same for both arrays and linked lists. Whereas, the time complexity of Quicksort is O(n^2) in the worst case scenario, making it inefficient for linked lists.
Moreover, Merge Sort utilizes the divide and conquer strategy, which makes it easier to sort linked lists. It does so by dividing the linked list into two halves, recursively sorting them and then merging them together.
Quicksort, on the other hand, works by selecting a pivot element, rearranging the elements such that elements smaller than the pivot are to its left and larger elements are to its right and then recursively applying the same process on the left and right subarrays. This process becomes difficult to implement on linked lists, as searching for elements and rearranging pointers can cause performance issues.
Therefore, Merge Sort is a better option than Quicksort for sorting linked lists due to its efficient time complexity and ease of implementation.
Program to Delete Odd-Positioned Nodes from a Circular Linked List
/*
* A node of the circular linked list.
*/
class Node {
int data;
Node next;
Node(int data) {
this.data = data;
next = null;
}
}
/*
* Function to delete odd-positioned nodes from a circular linked list.
*/
public void deleteOddNodes(Node head) {
Node current = head;
Node prev = null;
int index = 1;
// Traverse the circular linked list and delete odd-positioned nodes.
while (current != null) {
if (index % 2 != 0) { // Delete odd-positioned node.
if (current == head) { // If current node is head.
// Move to last node of the linked list.
Node temp = head;
while (temp.next != head) {
temp = temp.next;
}
// Update the head and previous pointers.
head = current.next;
temp.next = head;
prev = temp;
} else { // If current node is not head.
prev.next = current.next;
}
// Delete the current node.
current = current.next;
} else { // Keep even-positioned node.
prev = current;
current = current.next;
}
index++;
}
}
The above program uses a class `Node` to represent a node in the circular linked list. In the `deleteOddNodes` function, we traverse the circular linked list and delete nodes at odd positions (1-based indexing), while keeping the nodes at even positions. We also update the pointers of the linked list accordingly.
Extracting all leaves from a binary tree into a doubly linked list (DLL)
Code:
python
class Node:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
def extract_leaves(root):
# Function to extract leaves from a binary tree and return them as a doubly linked list (DLL)
# Input: root - Root node of the binary tree
# Output: tail - Tail node of the DLL
if not root:
return None
if not root.left and not root.right:
# Leaf node. Remove it from the tree and return as DLL node
return root
left_tail = extract_leaves(root.left)
right_tail = extract_leaves(root.right)
if left_tail:
# Connect the leaf nodes from the left and right subtrees to the root
left_tail.right = root.right
if root.right:
root.right.left = left_tail
root.right = root.left
root.left = None
# Return the tail node of the merged DLL
if right_tail:
return right_tail
else:
return left_tail
This code defines a function "extract_leaves" that takes the root node of a binary tree as input and returns the tail node of a doubly linked list containing all the leaf nodes of the tree.
The function works by recursively calling itself on the left and right children of the root node, until a leaf node is reached. The leaf node is removed from the tree and returned as a node in the DLL.
The remaining non-leaf nodes are then connected to the leaf nodes from the left and right subtrees to form the DLL.
Converting a 2D matrix to a Linked List
class Node:
def __init__(self, val):
self.val = val
self.right = None
self.down = None
def convert_matrix_to_linked_list(matrix):
rows = len(matrix)
cols = len(matrix[0])
# Creating nodes for each element in the matrix
nodes = [[Node(matrix[i][j]) for j in range(cols)] for i in range(rows)]
# Linking nodes to their right and down elements
for i in range(rows):
for j in range(cols):
if j < cols-1:
nodes[i][j].right = nodes[i][j+1]
if i < rows-1:
nodes[i][j].down = nodes[i+1][j]
# Starting from the top-left node and displaying the linked list
current = nodes[0][0]
while current:
print(current.val, end=" ")
current = current.right if current.right else current.down
The above code defines a Node class having a value and pointers to right and down nodes. The
convert_matrix_to_linked_list
function takes a 2D matrix and returns a linked list where each node is linked to its next right and down node. This is achieved by first creating nodes for each element in the matrix and then linking them to their right and down elements. Finally, the linked list is displayed starting from the top-left node.
Finding Pairs in a Doubly-Linked List
This program is designed to find pairs in a sorted doubly-linked list of positive, distinct entries that add up to a provided value 'val'. The program accomplishes this task without using any extra memory space. It has an expected time complexity of O(N) and an expected space complexity of O(1).
// Define the Node class for a doubly-linked list
class Node {
int data;
Node next, prev;
// Constructor to create a new node
Node(int d) { data = d; }
}
// Define the function to find pairs that add up to 'val'
void findPairs(Node head, int val) {
Node first = head;
Node second = head;
// Find the rightmost node
while (second.next != null)
second = second.next;
// Create a variable to check if pairs have been found
boolean pairFound = false;
// Loop through the linked list
while (first != null && second != null && first != second && second.next != first) {
// If a pair is found, print it
if (first.data + second.data == val) {
System.out.println("(" + first.data + ", " + second.data + ")");
pairFound = true;
first = first.next;
second = second.prev;
}
// If the sum of the current pair is too small, move the left pointer
else if (first.data + second.data < val)
first = first.next;
// If the sum of the current pair is too large, move the right pointer
else
second = second.prev;
}
// If no pairs are found, print that there are no pairs
if (!pairFound)
System.out.println("No pairs found.");
}
Constructing a Doubly Linked List from a Ternary Tree
We can construct a doubly linked list from a ternary tree by traversing the tree in the following manner:
1. Visit the left subtree recursively.
2. Visit the middle subtree recursively.
3. Visit the right subtree recursively.
Whenever we visit a node, we add it to the end of the linked list using the following steps:
1. If the linked list is empty, the current node becomes the head and tail of the linked list.
2. If the linked list is not empty, we append the current node to the end of the linked list and update the tail to be the current node.
Below is the Python code that implements the above algorithm:
python
class TernaryTreeNode:
def __init__(self, val=None):
self.val = val
self.left = None
self.mid = None
self.right = None
class DoublyLinkedNode:
def __init__(self, val=None):
self.val = val
self.prev = None
self.next = None
class DoublyLinkedList:
def __init__(self):
self.head = None
self.tail = None
def append(self, node):
if not self.head:
self.head = self.tail = node
else:
self.tail.next = node
node.prev = self.tail
self.tail = node
def ternary_tree_to_doubly_linked_list(node):
if not node:
return None
linked_list = DoublyLinkedList()
ternary_tree_to_doubly_linked_list(node.left)
ternary_tree_to_doubly_linked_list(node.mid)
ternary_tree_to_doubly_linked_list(node.right)
linked_list.append(DoublyLinkedNode(node.val))
return linked_list.head
Removing Points from Linked List
Given a linked list of coordinates where neighboring points form either a vertical or horizontal line, we can remove points in between the starting and ending points of the line. This can be done using the following steps:
- Traverse the linked list, keeping track of the current point and the previous point.
- Check if the current point and the previous point form a horizontal or vertical line with the next point. If they do, continue traversing. If not, remove the points in between the starting and ending points of the line.
- Repeat step two until the end of the linked list is reached.
/**
* Node class for creating linked list
*/
class Node {
int x, y;
Node next;
public Node(int x, int y) {
this.x = x;
this.y = y;
next = null;
}
}
/**
* Method for removing points from linked list
*/
void removePoints(Node head) {
Node curr = head;
Node prev = null;
while (curr != null) {
Node next = curr.next;
// Check if current point and previous point form horizontal or vertical line with next point
if (next != null && ((curr.x == prev.x && curr.x == next.x) || (curr.y == prev.y && curr.y == next.y))) {
prev = curr;
curr = next;
} else {
prev.next = next;
curr = next;
}
}
}
Modifying a Linked List to Move Even Numbers before Odd Numbers
To modify a linked list of integers so that all even numbers appear before all odd numbers, while keeping the even and odd numbers in the same order, we can follow the below approach:
1. Traverse the linked list using a pointer and identify the first odd number node (if any).
2. While traversing the linked list, if an even number node is encountered, move it to the front of the linked list.
3. When we reach the end of the linked list or the first odd number node, return to the beginning of the list and repeat step 1 until we have moved all even number nodes to the front ahead of all odd numbers.
Here's an implementation of the above approach in Python:
python
class Node:
# class to create node object
def __init__(self, data):
self.data = data
self.next = None
def move_evens_to_front(head):
# function to move all even number nodes to the front of a linked list
# initially, no odd nodes and even nodes present
odd_start = None
odd_end = None
even_start = None
even_end = None
# traverse the linked list
while head != None:
next_node = head.next
head.next = None
# if the current node is an even number
if head.data % 2 == 0:
# add it to the even list
if even_start == None:
even_start = head
even_end = even_start
else:
even_end.next = head
even_end = even_end.next
# if the current node is an odd number
else:
# add it to the odd list
if odd_start == None:
odd_start = head
odd_end = odd_start
else:
odd_end.next = head
odd_end = odd_end.next
# move to the next node
head = next_node
# if even nodes are not present
if even_start == None:
return odd_start
# otherwise, add even nodes to the beginning of the odd nodes list
even_end.next = odd_start
return even_start
We can call this function with the head of our original linked list and it will return a new linked list with even numbers appearing before odd numbers, while preserving the original order of even and odd numbers.
Finding Sum of Last N Nodes in a Linked List
To find the sum of the last N nodes of a linked list, we can follow the below approach:
1. Traverse the linked list and maintain a counter to count the number of nodes in the list. 2. Calculate the difference between the total number of nodes and the given value N. Let's call this difference as K. 3. Traverse the linked list again and stop when we reach the Kth node from the start. 4. Add the values of the nodes from Kth node till the end, which gives us the sum of last N nodes in the linked list.
By following this approach, we can find the sum of last N nodes in a single traversal of the linked list. The time complexity of this approach is O(n), where n is the total number of nodes in the linked list.
Function to sort a linked list based on actual values
Here's an implementation of a function to sort a linked list based on actual values, assuming the input list is already sorted based on absolute values:
Code
#include <stdio.h>
#include <stdlib.h>
// Define the struct for a singly linked list node
struct ListNode {
int val;
struct ListNode* next;
};
// Function to insert a new node at the beginning of a linked list
void push(struct ListNode** head_ref, int new_val) {
struct ListNode* new_node = (struct ListNode*)malloc(sizeof(struct ListNode));
new_node->val = new_val;
new_node->next = *head_ref;
*head_ref = new_node;
}
// Function to print the contents of a linked list
void printList(struct ListNode* node) {
while (node != NULL) {
printf("%d ", node->val);
node = node->next;
}
printf("\n");
}
// Function to sort a linked list based on actual values in O(n) time
struct ListNode* sortList(struct ListNode* head) {
struct ListNode* curr = head;
struct ListNode* prev = NULL;
struct ListNode* temp = NULL;
int swapped = 0;
// Bubble sort loop to sort the list
do {
swapped = 0;
curr = head;
while (curr->next != temp) {
if (curr->val > curr->next->val) {
// Swap the nodes
struct ListNode* tmp = curr->next;
curr->next = curr->next->next;
tmp->next = curr;
if (prev == NULL) {
head = prev = tmp;
} else {
prev->next = tmp;
prev = tmp;
}
swapped = 1;
} else {
prev = curr;
curr = curr->next;
}
}
temp = curr;
} while (swapped);
return head;
}
// Driver code to test the function
int main() {
// Create a linked list: 1 -> -2 -> 3 -> -4 -> -5
struct ListNode* head = NULL;
push(&head, -5);
push(&head, -4);
push(&head, 3);
push(&head, -2);
push(&head, 1);
printf("Given linked list:\n");
printList(head);
head = sortList(head);
printf("\nLinked list after sorting by actual values:\n");
printList(head);
return 0;
}
Explanation: - We start by defining the `ListNode` struct that represents a singly linked list node. - We implement a `push` function to insert a new node at the beginning of the list. - We implement a `printList` function to print the contents of a linked list. - The `sortList` function uses a modified bubble sort algorithm to sort the list based on actual values in O(n) time. - We test the function by creating a linked list and printing the unsorted and sorted versions of the list.
Note: This implementation assumes that the input list contains only integers. If the list contains other data types, the function should be modified accordingly.
Linked List Interview Questions for Experienced: Finding the Length of a Linked List with a Cycle
To find the length of a linked list that contains a cycle, we can use the Floyd's cycle-finding algorithm.
Code:
python
def find_length(head):
"""
This function finds the length of a linked list with cycle, using Floyd's cycle-finding algorithm.
:param head: The head node of the linked list.
:return: The length of the linked list.
"""
# initializing variables
slow_ptr = head
fast_ptr = head
cycle_found = False
length = 0
# traversing through the linked list
while(slow_ptr and fast_ptr and fast_ptr.next):
# moving slow_ptr to the next node
slow_ptr = slow_ptr.next
# moving fast_ptr to the next to next node
fast_ptr = fast_ptr.next.next
# if there exists a cycle in the linked list
if slow_ptr == fast_ptr:
cycle_found = True
break
# finding the length of the cycle
if cycle_found:
cur_ptr = fast_ptr
while (cur_ptr.next != fast_ptr):
cur_ptr = cur_ptr.next
length += 1
length += 1
# finding the length of the linked list before the cycle starts
length_before_cycle = 0
ptr = head
while(ptr and ptr != slow_ptr):
ptr = ptr.next
length_before_cycle += 1
# total length of the linked list
return length_before_cycle + length
In this code, we first initialize two pointers (slow_ptr and fast_ptr) to the head of the linked list and then traverse through the list. Using Floyd's cycle-finding algorithm, we check if there exists a cycle in the linked list. Once we detect the cycle, we find the length of the cycle and the length of the linked list before the cycle starts. Finally, we return the total length of the linked list by adding the length of the cycle and the length of the linked list before the cycle starts.
Adding Polynomial Expressions using Linked Lists
Here is a function that can add two polynomial expressions represented as linked lists. It essentially adds the coefficients that have the same variable powers.
// Definition of a polynomial term node
class PolynomialTermNode {
int coefficient;
int power;
PolynomialTermNode next;
}
// Function to add two polynomial expressions represented by linked lists
public PolynomialTermNode addPolynomials(PolynomialTermNode poly1, PolynomialTermNode poly2) {
PolynomialTermNode result = new PolynomialTermNode();
PolynomialTermNode current = result;
while(poly1 != null && poly2 != null) {
if(poly1.power == poly2.power) {
current.coefficient = poly1.coefficient + poly2.coefficient;
current.power = poly1.power;
poly1 = poly1.next;
poly2 = poly2.next;
} else if(poly1.power > poly2.power) {
current.coefficient = poly1.coefficient;
current.power = poly1.power;
poly1 = poly1.next;
} else {
current.coefficient = poly2.coefficient;
current.power = poly2.power;
poly2 = poly2.next;
}
if(poly1 != null || poly2 != null) {
current.next = new PolynomialTermNode();
current = current.next;
}
}
// Handling the remaining polynomial terms in case one list is longer than the other
while(poly1 != null) {
current.coefficient = poly1.coefficient;
current.power = poly1.power;
poly1 = poly1.next;
if(poly1 != null) {
current.next = new PolynomialTermNode();
current = current.next;
}
}
while(poly2 != null) {
current.coefficient = poly2.coefficient;
current.power = poly2.power;
poly2 = poly2.next;
if(poly2 != null) {
current.next = new PolynomialTermNode();
current = current.next;
}
}
return result;
}
Finding the Merging Point of Two Lists with Varying Lengths in Python
Given two lists with varying lengths, we need to find the point at which they merge. One way to do this is by using two pointers.
Code:
def get_merge_point(list1, list2): current1 = list1.head # Pointer for list1 current2 = list2.head # Pointer for list2 # Traverse the two lists while current1 != current2: # If the end of List 1 is reached, switch to List 2 if current1 is None: current1 = list2.head else: current1 = current1.next # If the end of List 2 is reached, switch to List 1 if current2 is None: current2 = list1.head else: current2 = current2.next # Return the merging point return current1.data
In this code, we start by initializing two pointers - one for each list. We then traverse the two lists simultaneously, moving the pointers one node at a time.
If a pointer reaches the end of its list, we switch it to the head of the other list. This way, the pointers are always tracing the longer list until they reach the point where the two lists merge.
Once the pointers meet at this merging point, we return the data of that node.
Counting Triplets in a Sorted Doubly Linked List
Given a value X and a sorted doubly linked list of different nodes where no two nodes have the same data. The task is to count the number of triplets in the list that add up to X. The expected time complexity is O(N^2) and the expected space complexity is O(1).
// Node class to create a node of linked list class Node { int data; Node prev, next; Node(int val) { data = val; prev = next = null; } } // Function to count triplets that sum to X static int countTriplets(Node head, int X) { Node i, j, k; int count = 0; // Initialize pointers i and j for (i = head; i != null; i = i.next) { for (j = i.next; j != null; j = j.next) { // Initialize k as the largest node // among the nodes next to j k = j.next; // Traverse the remaining nodes // to find the triplets while (k != null) { if ((i.data + j.data + k.data) == X) { count++; } k = k.next; } } } // Return the count of triplets return count; }
Explanation:
We use three pointers i, j, and k to traverse the list and find triplets which sum up to X. We initialize i and j at the first two nodes of the list and traverse till we find the last node of the list. To ensure that k is the largest node among the nodes next to j, we initialize it to the next node of j and traverse till the last node of the list. We then check if the sum of i, j, and k is equal to X. If true, we increment the count. Finally, we return the count of triplets.
Finding Length of Longest Palindrome Linked List
Given a linked list, this program finds the length of the longest palindrome list that appears in the given linked list using O(1) extra space.
class Node { int data; Node next; Node(int d) { data = d; next = null; } } public class PalindromeLinkedList { public static int getLengthOfLongestPalindrome(Node head) { int maxLength = 0; // Check each possible center of palindrome for (Node curr = head; curr != null; curr = curr.next) { int length = 0; Node even = curr; Node odd = curr.next; // Check for even length palindrome while (even != null && even.next != null && even.data == even.next.data) { length += 2; even = even.next.next; } // Check for odd length palindrome while (odd != null && odd.next != null && curr.data == odd.next.data) { length += 2; odd = odd.next.next; } // If longest palindrome seen until now is smaller // than the current palindrome, update maxLength if (maxLength < length + 1) { maxLength = length + 1; } } return maxLength; } public static void main(String[] args) { // Sample input linked list Node head = new Node(2); head.next = new Node(4); head.next.next = new Node(3); head.next.next.next = new Node(4); head.next.next.next.next = new Node(2); int lengthOfLongestPalindrome = getLengthOfLongestPalindrome(head); System.out.println("Length of longest palindrome in the given linked list is " + lengthOfLongestPalindrome); } }
Algorithm to Update "Arbitrary" Pointer in Singly Linked List
To update the "arbitrary" pointer in a singly linked list to point to the next node with a greater value, the following algorithm can be implemented:
1. Traverse the linked list from the beginning to end. 2. For each node, compare its value with the values of all following nodes. 3. If a node with a greater value is found, update the "arbitrary" pointer of the current node to point to that node. 4. If no node with a greater value is found, leave the "arbitrary" pointer of the current node as null. 5. Continue traversal until the end of the linked list is reached.
This algorithm ensures that each node's "arbitrary" pointer points to the next node with a greater value, if one exists. If there are multiple nodes with the same greatest value, the "arbitrary" pointer will point to the first occurrence of that value. If no node with a greater value is found, the "arbitrary" pointer will remain null.
Creating a Doubly Linked List with One Address Field
In a standard doubly linked list, two address fields are used to store the addresses of the previous and the next nodes. However, using a XOR linked list, we can create a doubly linked list with only one space for the address field in every node.
Here's an example implementation:
struct Node { int data; Node* xor_ptr; // Pointer which stores XOR of one previous and one next nodes }; Node* XOR(Node *a, Node *b) { // Returns XOR of two nodes return reinterpret_cast<Node *> (reinterpret_cast<uintptr_t> (a) ^ reinterpret_cast<uintptr_t> (b)); } class DoublyLinkedList { Node *head; public: DoublyLinkedList() { head = NULL; } void insert_end(int data) { Node *new_node = new Node; new_node->data = data; // If list is empty, simply make new node as head if (head == NULL) { new_node->xor_ptr = XOR(NULL, NULL); head = new_node; } else { Node *prev = NULL; Node *curr = head; Node *next = XOR(prev, curr->xor_ptr); while (next != NULL) { // traverse to the end of the list prev = curr; curr = next; next = XOR(prev, curr->xor_ptr); } // add new node at the end of the list new_node->xor_ptr = XOR(curr, NULL); curr->xor_ptr = XOR(prev, new_node); } } void print_list() const { // print the list in forward direction Node *prev = NULL; Node *curr = head; Node *next; cout << "Doubly linked list (in forward direction): "; while (curr) { cout << curr->data << " "; next = XOR(prev, curr->xor_ptr); prev = curr; curr = next; } cout << endl; } };
The XOR function takes two node pointers as input and returns the XOR of their addresses. We use this function to calculate the XOR of the previous and the next nodes while traversing the list.
In the insert_end function, we create a new node and add it at the end of the list. If the list is empty, we simply make the new node the head of the list. Otherwise, we traverse the list from the head till the end, and add the new node at the end.
The print_list function is used to print the list in the forward direction (since we can't traverse the list backwards using XOR pointers alone).
By using XOR pointers, we are able to create a doubly linked list with only one space for the address field in every node.
Flattening and Sorting a Linked List of Linked Lists
To flatten and sort a linked list of linked lists, we can follow the following approach:
1. Traverse the linked list and for each node, merge its linked list with the current result linked list. 2. Keep merging until we reach the end of the linked list. 3. Sort the final merged linked list using any sorting algorithm (e.g. merge sort, quick sort, etc.).
We can implement this approach as follows:
// Definition for a linked list node class LinkedListNode { int val; LinkedListNode next; LinkedListNode down; LinkedListNode(int val) { this.val = val; this.next = null; this.down = null; } } // Function to merge two linked lists private LinkedListNode mergeLinkedLists(LinkedListNode l1, LinkedListNode l2) { if (l1 == null) { return l2; } if (l2 == null) { return l1; } // Pick the smaller value and recur if (l1.val < l2.val) { l1.down = mergeLinkedLists(l1.down, l2); return l1; } else { l2.down = mergeLinkedLists(l1, l2.down); return l2; } } // Function to flatten the linked list and sort it public LinkedListNode flattenAndSortLinkedList(LinkedListNode head) { if (head == null || head.next == null) { return head; } // Recursively flatten and sort the linked list head.next = flattenAndSortLinkedList(head.next); head = mergeLinkedLists(head, head.next); return head; }
In the above code, we first define a `LinkedListNode` class to represent each node of the linked list. We also define a helper function `mergeLinkedLists` to merge two linked lists recursively.
Then we define the main function `flattenAndSortLinkedList` which takes the head of the linked list as input. We first check if the `head` node is null or if it is the last node in the linked list. If true, we return the node itself.
Otherwise, we recursively flatten and sort the linked list by calling the `flattenAndSortLinkedList` function on the next node of the `head` node. We then merge the `head` node and the next node using the `mergeLinkedLists` function. Finally, we return the `head` node after merging.
With this approach, we can efficiently flatten and sort a linked list of linked lists.
Technical Interview Guides
Here are guides for technical interviews, categorized from introductory to advanced levels.
View AllBest MCQ
As part of their written examination, numerous tech companies necessitate candidates to complete multiple-choice questions (MCQs) assessing their technical aptitude.
View MCQ's