Circular Linked List
What is Circular Linked List
A circular linked list is structured like a normal linked list except the last node's next pointer points back to the first node instead of to null, forming a continuous loop instead of a straight line.
Example: What is Circular Linked List
#include <iostream>
using namespace std;
struct Node { int data; Node* next; };
int main() {
Node* a = new Node{1, nullptr};
Node* b = new Node{2, nullptr};
Node* c = new Node{3, nullptr};
a->next = b; b->next = c; c->next = a;
cout << "last node points back to first: " << (c->next == a) << endl;
return 0;
}
class Node { int data; Node next; Node(int d) { data = d; } }
public class Main {
public static void main(String[] args) {
Node a = new Node(1), b = new Node(2), c = new Node(3);
a.next = b; b.next = c; c.next = a;
System.out.println("last node points back to first: " + (c.next == a));
}
}
class Node:
def __init__(self, data):
self.data = data
self.next = None
a, b, c = Node(1), Node(2), Node(3)
a.next = b
b.next = c
c.next = a
print("last node points back to first:", c.next is a)
#include <stdio.h>
#include <stdlib.h>
struct Node { int data; struct Node *next; };
int main() {
struct Node *a = malloc(sizeof(struct Node));
struct Node *b = malloc(sizeof(struct Node));
struct Node *c = malloc(sizeof(struct Node));
a->data = 1; b->data = 2; c->data = 3;
a->next = b; b->next = c; c->next = a;
printf("last node points back to first: %d\n", c->next == a);
return 0;
}
Login to try C/C++/Java code in the editor
Traversal
Because there's no null at the end to signal stop, traversal has to explicitly check whether you've returned to the node you started from, otherwise a naive loop would run forever.
Example: Traversal
#include <iostream>
using namespace std;
struct Node { int data; Node* next; };
int main() {
Node* a = new Node{1, nullptr};
Node* b = new Node{2, nullptr};
Node* c = new Node{3, nullptr};
a->next = b; b->next = c; c->next = a;
Node* curr = a;
do {
cout << curr->data << " ";
curr = curr->next;
} while (curr != a);
cout << endl;
return 0;
}
class Node { int data; Node next; Node(int d) { data = d; } }
public class Main {
public static void main(String[] args) {
Node a = new Node(1), b = new Node(2), c = new Node(3);
a.next = b; b.next = c; c.next = a;
Node curr = a;
do {
System.out.print(curr.data + " ");
curr = curr.next;
} while (curr != a);
}
}
class Node:
def __init__(self, data):
self.data = data
self.next = None
a, b, c = Node(1), Node(2), Node(3)
a.next = b
b.next = c
c.next = a
curr = a
while True:
print(curr.data, end=" ")
curr = curr.next
if curr is a:
break
#include <stdio.h>
#include <stdlib.h>
struct Node { int data; struct Node *next; };
int main() {
struct Node *a = malloc(sizeof(struct Node));
struct Node *b = malloc(sizeof(struct Node));
struct Node *c = malloc(sizeof(struct Node));
a->data = 1; b->data = 2; c->data = 3;
a->next = b; b->next = c; c->next = a;
struct Node *curr = a;
do {
printf("%d ", curr->data);
curr = curr->next;
} while (curr != a);
printf("\n");
return 0;
}
Login to try C/C++/Java code in the editor
Insertion
Inserting a new node into a circular list just means redirecting the appropriate next pointers to route through the new node while preserving the loop, which is often simpler at the end since there's no special null case to handle.
Example: Insertion
#include <iostream>
using namespace std;
struct Node { int data; Node* next; };
int main() {
Node* a = new Node{1, nullptr};
Node* b = new Node{2, nullptr};
a->next = b; b->next = a;
Node* n = new Node{99, nullptr};
n->next = b->next;
b->next = n;
cout << "inserted after b: " << b->next->data << endl;
return 0;
}
class Node { int data; Node next; Node(int d) { data = d; } }
public class Main {
public static void main(String[] args) {
Node a = new Node(1), b = new Node(2);
a.next = b; b.next = a;
Node n = new Node(99);
n.next = b.next;
b.next = n;
System.out.println("inserted after b: " + b.next.data);
}
}
class Node:
def __init__(self, data):
self.data = data
self.next = None
a, b = Node(1), Node(2)
a.next = b
b.next = a
n = Node(99)
n.next = b.next
b.next = n
print("inserted after b:", b.next.data)
#include <stdio.h>
#include <stdlib.h>
struct Node { int data; struct Node *next; };
int main() {
struct Node *a = malloc(sizeof(struct Node));
struct Node *b = malloc(sizeof(struct Node));
a->data = 1; b->data = 2;
a->next = b; b->next = a;
struct Node *n = malloc(sizeof(struct Node));
n->data = 99;
n->next = b->next;
b->next = n;
printf("inserted after b: %d\n", b->next->data);
return 0;
}
Login to try C/C++/Java code in the editor
Advantages
Because any node can serve as a natural entry point back into the whole sequence, circular lists are a good fit for anything that cycles repeatedly, like round-robin CPU scheduling or a rotating playlist.
Example: Advantages
#include <iostream>
using namespace std;
struct Node { int id; Node* next; };
int main() {
Node* p1 = new Node{1, nullptr};
Node* p2 = new Node{2, nullptr};
Node* p3 = new Node{3, nullptr};
p1->next = p2; p2->next = p3; p3->next = p1;
Node* curr = p1;
for (int round = 0; round < 2; round++) {
for (int i = 0; i < 3; i++) {
cout << "running process " << curr->id << endl;
curr = curr->next;
}
}
return 0;
}
class Node { int id; Node next; Node(int i) { id = i; } }
public class Main {
public static void main(String[] args) {
Node p1 = new Node(1), p2 = new Node(2), p3 = new Node(3);
p1.next = p2; p2.next = p3; p3.next = p1;
Node curr = p1;
for (int round = 0; round < 2; round++) {
for (int i = 0; i < 3; i++) {
System.out.println("running process " + curr.id);
curr = curr.next;
}
}
}
}
class Node:
def __init__(self, id_):
self.id = id_
self.next = None
p1, p2, p3 = Node(1), Node(2), Node(3)
p1.next = p2
p2.next = p3
p3.next = p1
curr = p1
for _ in range(2):
for _ in range(3):
print("running process", curr.id)
curr = curr.next
#include <stdio.h>
#include <stdlib.h>
struct Node { int id; struct Node *next; };
int main() {
struct Node *p1 = malloc(sizeof(struct Node));
struct Node *p2 = malloc(sizeof(struct Node));
struct Node *p3 = malloc(sizeof(struct Node));
p1->id = 1; p2->id = 2; p3->id = 3;
p1->next = p2; p2->next = p3; p3->next = p1;
struct Node *curr = p1;
for (int round = 0; round < 2; round++)
for (int i = 0; i < 3; i++) {
printf("running process %d\n", curr->id);
curr = curr->next;
}
return 0;
}
Login to try C/C++/Java code in the editor
Careful Traversal
The most common bug with circular lists is using an ordinary linked-list traversal pattern that checks for null: since that condition never becomes true, you have to explicitly track and compare against the starting node instead.
Example: Careful Traversal
#include <iostream>
using namespace std;
struct Node { int data; Node* next; };
int main() {
Node* a = new Node{1, nullptr};
Node* b = new Node{2, nullptr};
a->next = b; b->next = a;
int count = 0;
Node* curr = a;
do {
count++;
curr = curr->next;
} while (curr != a && count < 10);
cout << "visited " << count << " nodes (never null, so we compare to start)" << endl;
return 0;
}
class Node { int data; Node next; Node(int d) { data = d; } }
public class Main {
public static void main(String[] args) {
Node a = new Node(1), b = new Node(2);
a.next = b; b.next = a;
int count = 0;
Node curr = a;
do {
count++;
curr = curr.next;
} while (curr != a && count < 10);
System.out.println("visited " + count + " nodes (never null, so we compare to start)");
}
}
class Node:
def __init__(self, data):
self.data = data
self.next = None
a, b = Node(1), Node(2)
a.next = b
b.next = a
count = 0
curr = a
while True:
count += 1
curr = curr.next
if curr is a or count >= 10:
break
print("visited", count, "nodes (never None, so we compare to start)")
#include <stdio.h>
#include <stdlib.h>
struct Node { int data; struct Node *next; };
int main() {
struct Node *a = malloc(sizeof(struct Node));
struct Node *b = malloc(sizeof(struct Node));
a->data = 1; b->data = 2;
a->next = b; b->next = a;
int count = 0;
struct Node *curr = a;
do {
count++;
curr = curr->next;
} while (curr != a && count < 10);
printf("visited %d nodes (never NULL, so we compare to start)\n", count);
return 0;
}
Login to try C/C++/Java code in the editor
Chapter Quiz — Complete all 8 topics to unlock
0/8 topics done
Complete these topics first: