1. Introduction
In Computer Science, a linked list is a linear data structure in which a pointer in each element determines the order.
In this tutorial, we’ll show how to check if a linked list is a circular linked list.
2. Circular Linked List
Each element of a linked list contains a data field to store the list data and a pointer field to point to the next element in the sequence. We can use a pointer to point to the start element of a linked list:
In a regular linked list, the last element has no next element. Therefore, its pointer field is . However, in a circular linked list, the last element has a reference to one of the elements in the list:
3. Hash Table Solution
It is easy to see that if a linked list contains a cycle, we’ll eventually visit the same node twice when we traverse the linked list. Therefore, we can use a hash table to solve this problem:
algorithm isCircularList(head):
// INPUT
// head = first element of a linked list
// OUTPUT
// true if the linked list is circular, otherwise false
hashTable <- construct empty hash table
currentNode <- head
while currentNode != null:
if hashTable contains currentNode:
return true
else:
add currentNode into hashTable
currentNode <- currentNode.next
return false
This algorithm traverses the linked list and records each node’s reference in a hash table. We use a linked list node’s reference as its unique identifier. If we see the same reference again in the hash table, we can return to indicate a circular linked list. Otherwise, we’ll finally reach the node and return .
Let’s assume each hash table operation, such as insertion and searching, takes time. Then, this algorithm’s overall time complexity is as we traverse the whole linked list only once. The space complexity is also , as we need to store all the nodes into the hash table.
4. Solution With Two Pointers
To detect whether a linked list is a circular linked list, we can use two pointers with different speeds: a pointer and a pointer. We use these two pointers to traverse the linked list. The pointer moves one step at a time, and the pointer moves two steps.
If there is no cycle in the list, the pointer will eventually reach the last element whose pointer is and stop there.
For a circular linked list, let’s imagine the and pointers are two runners racing around a circular track. At the beginning, the runner passes the runner. However, it’ll eventually meet the runner again from behind. We can use the same idea to detect if there is a cycle in the linked list:
algorithm isCircularList(head):
// INPUT
// head = first element of a linked list
// OUTPUT
// true if the linked list is circular, otherwise false
if head is null:
return false
slow <- head
fast <- head.next
while slow != fast:
if fast is null or fast.next is null:
return false
slow <- slow.next
fast <- fast.next.next
return true
In this algorithm, we first have a sanity check on the input pointer. Then, we start two pointers, and , at different locations. In the loop, we advance the two pointers at different speeds. If the pointer reaches the terminated pointer, we can conclude that the linked list does not have a cycle. Otherwise, the two pointers will eventually meet. Then, we finish the loop and return to indicate a circular linked list.
5. Complexity Analysis of the Two-pointer Solution
If the linked list doesn’t have a cycle, the loop will finish when the pointer reaches the end. Therefore, the time complexity is in this case.
For a circular linked list, we need to calculate the number of steps to make the pointer catch the pointer. Let’s first break down the movement of the pointer into two stages.
In the first stage, the pointer takes steps to enter the cycle. At this point, the pointer has already in the cycle and is elements apart from the pointer in the linked list direction. In the following example, the distance between the two pointers is 3 elements since we need to advance the pointer 3 elements to catch the pointer in the cycle:
In the second stage, both pointers are in the cycle. The pointer moves 2 steps in each iteration, and the pointer moves 1 step. Therefore, the pointer can catch up 1 element in each iteration. Since the distance between these two pointers at the beginning is , we need iterations to make these two pointers meet.
Therefore, the total running time is , where is the number of elements between the and the start element of the cycle, and is the distance between the two pointers when the pointer reaches the cycle. Since is at most the cycle length, the overall time complexity is also .
The space complexity is as we only use two pointers ( and ) in the algorithm.
6. Conclusion
In this tutorial, we showed a sample circular linked list. Also, we discussed two linear-time algorithms that can check if a linked list is a circular linked list.