Skip to content

Commit b820941

Browse files
Added Circular Linked List Data Structure
1 parent a6732f9 commit b820941

File tree

4 files changed

+360
-0
lines changed

4 files changed

+360
-0
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
using System;
2+
using DataStructures.LinkedList.CircularLinkedList;
3+
using NUnit.Framework;
4+
5+
namespace DataStructures.Tests.LinkedList;
6+
7+
[TestFixture]
8+
public static class CircularLinkedListTests
9+
{
10+
[Test]
11+
public static void TestInsertAtBeginning()
12+
{
13+
var cll = new CircularLinkedList<int>();
14+
cll.InsertAtBeginning(10);
15+
cll.InsertAtBeginning(20);
16+
cll.InsertAtBeginning(30);
17+
18+
Assert.That("30 20 10", Is.EqualTo(GetDisplayOutput(cll).Trim()));
19+
}
20+
21+
[Test]
22+
public static void TestInsertAtEnd()
23+
{
24+
var cll = new CircularLinkedList<int>();
25+
cll.InsertAtEnd(10);
26+
cll.InsertAtEnd(20);
27+
cll.InsertAtEnd(30);
28+
29+
Assert.That("10 20 30", Is.EqualTo(GetDisplayOutput(cll).Trim()));
30+
}
31+
32+
[Test]
33+
public static void TestInsertAfter()
34+
{
35+
var cll = new CircularLinkedList<int>();
36+
cll.InsertAtEnd(10);
37+
cll.InsertAtEnd(20);
38+
cll.InsertAtEnd(30);
39+
40+
cll.InsertAfter(20, 25);
41+
Assert.That("10 20 25 30", Is.EqualTo(GetDisplayOutput(cll).Trim()));
42+
}
43+
44+
[Test]
45+
public static void TestDeleteNode()
46+
{
47+
var cll = new CircularLinkedList<int>();
48+
cll.InsertAtEnd(10);
49+
cll.InsertAtEnd(20);
50+
cll.InsertAtEnd(30);
51+
52+
cll.DeleteNode(20);
53+
Assert.That("10 30", Is.EqualTo(GetDisplayOutput(cll).Trim()));
54+
}
55+
56+
[Test]
57+
public static void TestDisplay()
58+
{
59+
var cll = new CircularLinkedList<int>();
60+
cll.InsertAtEnd(10);
61+
cll.InsertAtEnd(20);
62+
cll.InsertAtEnd(30);
63+
64+
Assert.That("10 20 30", Is.EqualTo(GetDisplayOutput(cll).Trim()));
65+
}
66+
67+
[Test]
68+
public static void TestDeleteFromEmptyList()
69+
{
70+
var cll = new CircularLinkedList<int>();
71+
cll.DeleteNode(10);
72+
Assert.That(cll.IsEmpty(), Is.EqualTo(true));
73+
}
74+
75+
[Test]
76+
public static void TestInsertInEmptyList()
77+
{
78+
var cll = new CircularLinkedList<int>();
79+
cll.InsertAtBeginning(10);
80+
Assert.That("10", Is.EqualTo(GetDisplayOutput(cll).Trim()));
81+
}
82+
83+
[Test]
84+
public static void TestInsertAfterOnNonExistingValue()
85+
{
86+
var cll = new CircularLinkedList<int>();
87+
cll.InsertAtEnd(10);
88+
cll.InsertAfter(99, 25); // 99 does not exist
89+
Assert.That("10", Is.EqualTo(GetDisplayOutput(cll).Trim()));
90+
}
91+
92+
[Test]
93+
public static void TestDeleteOnlyNode()
94+
{
95+
var cll = new CircularLinkedList<int>();
96+
cll.InsertAtBeginning(10);
97+
cll.DeleteNode(10);
98+
Assert.That(cll.IsEmpty(), Is.EqualTo(true));
99+
}
100+
101+
[Test]
102+
public static void TestDeleteHeadNode()
103+
{
104+
var cll = new CircularLinkedList<int>();
105+
cll.InsertAtEnd(10);
106+
cll.InsertAtEnd(20);
107+
cll.InsertAtEnd(30);
108+
cll.DeleteNode(10);
109+
Assert.That("20 30", Is.EqualTo(GetDisplayOutput(cll).Trim()));
110+
}
111+
112+
[Test]
113+
public static void TestDeleteTailNode()
114+
{
115+
var cll = new CircularLinkedList<int>();
116+
cll.InsertAtEnd(10);
117+
cll.InsertAtEnd(20);
118+
cll.InsertAtEnd(30);
119+
cll.DeleteNode(30);
120+
Assert.That("10 20", Is.EqualTo(GetDisplayOutput(cll).Trim()));
121+
}
122+
123+
/// <summary>
124+
/// Helper method to capture the output of the Display method for assertions.
125+
/// </summary>
126+
/// <param name="list">The CircularLinkedList instance.</param>
127+
/// <returns>A string representation of the list.</returns>
128+
private static string GetDisplayOutput(CircularLinkedList<int> list)
129+
{
130+
// Save the original output (the default Console output stream)
131+
var originalConsoleOut = Console.Out;
132+
133+
// Use a StringWriter to capture Console output
134+
using (var sw = new System.IO.StringWriter())
135+
{
136+
try
137+
{
138+
// Redirect Console output to StringWriter
139+
Console.SetOut(sw);
140+
141+
// Call the method that outputs to the console
142+
list.Display();
143+
144+
// Return the captured output
145+
return sw.ToString();
146+
}
147+
finally
148+
{
149+
// Restore the original Console output stream
150+
Console.SetOut(originalConsoleOut);
151+
}
152+
}
153+
}
154+
}
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
using System;
2+
3+
namespace DataStructures.LinkedList.CircularLinkedList
4+
{
5+
/// <summary>
6+
/// CircularLinkedList.
7+
/// @author Mohit Singh. <a href="https://github.com/mohit-gogitter">mohit-gogitter</a>
8+
/// </summary>
9+
/// <typeparam name="T">The generic type parameter.</typeparam>
10+
public class CircularLinkedList<T>
11+
{
12+
/// <summary>
13+
/// Points to the last node in the Circular Linked List.
14+
/// </summary>
15+
private CircularLinkedListNode<T>? tail;
16+
17+
/// <summary>
18+
/// Initializes a new instance of the <see cref="CircularLinkedList{T}"/> class.
19+
/// </summary>
20+
public CircularLinkedList()
21+
{
22+
tail = null;
23+
}
24+
25+
/// <summary>
26+
/// Determines whether the Circular Linked List is empty.
27+
/// </summary>
28+
/// <returns>True if the list is empty; otherwise, false.</returns>
29+
public bool IsEmpty()
30+
{
31+
return tail == null;
32+
}
33+
34+
/// <summary>
35+
/// Inserts a new node at the beginning of the Circular Linked List.
36+
/// </summary>
37+
/// <param name="data">The data to insert into the new node.</param>
38+
public void InsertAtBeginning(T data)
39+
{
40+
var newNode = new CircularLinkedListNode<T>(data);
41+
if (IsEmpty())
42+
{
43+
tail = newNode;
44+
tail.Next = tail;
45+
}
46+
else
47+
{
48+
newNode.Next = tail!.Next;
49+
tail.Next = newNode;
50+
}
51+
}
52+
53+
/// <summary>
54+
/// Inserts a new node at the end of the Circular Linked List.
55+
/// </summary>
56+
/// <param name="data">The data to insert into the new node.</param>
57+
public void InsertAtEnd(T data)
58+
{
59+
var newNode = new CircularLinkedListNode<T>(data);
60+
if (IsEmpty())
61+
{
62+
tail = newNode;
63+
tail.Next = tail;
64+
}
65+
else
66+
{
67+
newNode.Next = tail!.Next;
68+
tail.Next = newNode;
69+
tail = newNode;
70+
}
71+
}
72+
73+
/// <summary>
74+
/// Inserts a new node after a specific value in the list.
75+
/// </summary>
76+
/// <param name="value">The value to insert the node after.</param>
77+
/// <param name="data">The data to insert into the new node.</param>
78+
public void InsertAfter(T value, T data)
79+
{
80+
if (IsEmpty())
81+
{
82+
Console.WriteLine("List is empty.");
83+
return;
84+
}
85+
86+
var current = tail!.Next;
87+
do
88+
{
89+
if (current!.Data!.Equals(value))
90+
{
91+
var newNode = new CircularLinkedListNode<T>(data);
92+
newNode.Next = current.Next;
93+
current.Next = newNode;
94+
95+
if (current == tail)
96+
{
97+
tail = newNode;
98+
}
99+
100+
return;
101+
}
102+
103+
current = current.Next;
104+
}
105+
while (current != tail.Next);
106+
107+
Console.WriteLine($"Node with value {value} not found.");
108+
}
109+
110+
/// <summary>
111+
/// Deletes a node with a specific value from the list.
112+
/// </summary>
113+
/// <param name="value">The value of the node to delete.</param>
114+
public void DeleteNode(T value)
115+
{
116+
if (IsEmpty())
117+
{
118+
Console.WriteLine("List is empty.");
119+
return;
120+
}
121+
122+
var current = tail!.Next;
123+
var previous = tail;
124+
125+
do
126+
{
127+
if (current!.Data!.Equals(value))
128+
{
129+
if (current == tail && current.Next == tail)
130+
{
131+
tail = null;
132+
}
133+
else if (current == tail)
134+
{
135+
previous!.Next = tail.Next;
136+
tail = previous;
137+
}
138+
else if (current == tail.Next)
139+
{
140+
tail.Next = current.Next;
141+
}
142+
else
143+
{
144+
previous!.Next = current.Next;
145+
}
146+
147+
Console.WriteLine($"Node with value {value} deleted.");
148+
return;
149+
}
150+
151+
previous = current;
152+
current = current.Next;
153+
}
154+
while (current != tail!.Next);
155+
156+
Console.WriteLine($"Node with value {value} not found.");
157+
}
158+
159+
/// <summary>
160+
/// Displays the contents of the Circular Linked List.
161+
/// </summary>
162+
public void Display()
163+
{
164+
if (IsEmpty())
165+
{
166+
Console.WriteLine("List is empty.");
167+
return;
168+
}
169+
170+
CircularLinkedListNode<T>? current = tail!.Next;
171+
do
172+
{
173+
Console.Write($"{current!.Data} ");
174+
current = current.Next;
175+
}
176+
while (current != tail!.Next);
177+
178+
Console.WriteLine();
179+
}
180+
}
181+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
namespace DataStructures.LinkedList.CircularLinkedList
2+
{
3+
/// <summary>
4+
/// Represents a node in the Circular Linked List.
5+
/// Each node contains generic data and a reference to the next node.
6+
/// </summary>
7+
/// <typeparam name="T">The type of the data stored in the node.</typeparam>
8+
/// <remarks>
9+
/// Initializes a new instance of the <see cref="CircularLinkedListNode{T}"/> class.
10+
/// </remarks>
11+
/// <param name="data">The data to be stored in the node.</param>
12+
public class CircularLinkedListNode<T>(T data)
13+
{
14+
/// <summary>
15+
/// Gets or sets the data for the node.
16+
/// </summary>
17+
public T Data { get; set; } = data;
18+
19+
/// <summary>
20+
/// Gets or sets the reference to the next node in the list.
21+
/// </summary>
22+
public CircularLinkedListNode<T>? Next { get; set; } = null;
23+
}
24+
}

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ find more than one implementation for the same objective but using different alg
263263
* [Singly Linked List](./DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedList.cs)
264264
* [Doubly Linked List](./DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedList.cs)
265265
* [Skip List](./DataStructures/LinkedList/SkipList/SkipList.cs)
266+
* [Circular Linked List](./DataStructures/LinkedList/CircularLinkedList/CircularLinkedList.cs)
266267
* [Graph](./DataStructures/Graph)
267268
* [Directed Weighted Graph Via Adjacency Matrix](./DataStructures/Graph/DirectedWeightedGraph.cs)
268269
* [Disjoint Set](./DataStructures/DisjointSet)

0 commit comments

Comments
 (0)