Question: Given a Linked List, we need to find the middle of the list and print the number.
Input: 4, 8, 15, 16, 23, 42, 99
Output: 16
This is a very basic question and is a part of a bigger problem. However, there are several approaches to solve the above problem.
BRUTE-FORCE APPROACH
In this approach, we count the number of nodes in the list for each of the node and see whether it is the middle.
struct node * bruteForce(struct node * head)
{
// making 2 temporary variables
struct node * temp1 = head;
struct node * temp2 = head;
// index for current node
int index = 1;
while(temp2 != NULL)
{
// to count the number of nodes
int count = 0;
// counting nodes for each node
temp 1 = head;
while(temp1 != NULL)
{
count++;
temp1 = temp1 -> next;
}
// the terminating condition
if(index == (count/2))
break;
index++;
temp2 = temp2 -> next;
}
// the temp2 points to the middle
return temp2;
}
Time Complexity: O(n2)
Space Complexity: O(1)
MORE SIMPLIFIED APPROACH
In this approach, we will scan the entire list and count the number of nodes. We divide the number by 2 and then again traverse the list up-to that node.
struct node * middleInTwoScans(struct node * head)
{
struct node * temp = head;
// counting the number of nodes
int count = 0;
while(temp != NULL)
{
count++;
temp = temp -> next;
}
// to get the middle node count
count = count/2;
// returning to first position
temp = head;
// traversing for n/2 times
while(count--)
temp = temp -> next;
// temp points at middle node
return temp;
}
Time Complexity: Time for finding the length + Time for locating middle node = O(n) + O(n) ≈ O(n)
Space Complexity: O(1)
USING HASH TABLE
What we can do is create a hash table and store the index of all the nodes in the List. Then to get the middle node, we can directly point to the node (n/2), where n is the size of the Linked List.
struct node * hashTableMiddle(struct node * head)
{
struct node * temp = head;
int count = 0;
while(temp)
{
count++;
temp = temp -> next;
}
// using array to create hash table
struct node * arr = (struct node *)malloc(sizeof(struct node)*count);
temp = head;
count = 0;
while(temp)
{
arr[count] = temp -> data;
count++;
temp = temp -> next;
}
return arr[(count/2)];
}
Time Complexity: O(n)
Space Complexity: O(n)
USING ONLY ONE SCAN – THE MOST EFFICIENT WAY
We can solve this problem using only one scan on the Linked List. The approach lies in a simple trick of using two pointers to traverse the list.
- ptr1 travels one node at a time
- ptr2 travels two nodes a time.
Thus, when ptr2 reaches the end of the Linked List, ptr1 will point at the middle of the Linked List.
// implementing a function that returns the middle of a Linked List
struct node * findMiddleOfLinkedList(struct node * head)
{
// a pointer that travels one node a time
struct node * slowPtr = head;
// a pointer that travels two nodes at a time
struct node * fastPtr = head;
while(fastPtr -> next != NULL)
{
// the slow Ptr moves one step
slowPtr = slowPtr -> next;
// the fast Ptr moves two steps
fastPtr = fastPtr -> next;
if(fastPtr == NULL)
break;
fastPtr = fastPtr -> next;
if(fastPtr == NULL)
break;
}
// the slow Ptr now points at the middle of the Linked List
return slowPtr;
}
Time Complexity: O(n)
Space Complexity: O(1)
You can download the working sample of the code here implementing the last method. Open it using any of your favorite editor (gEdit, Notepad++, wordpad etc…)