Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 208 additions & 0 deletions DataStructures.Tests/LinkedList/CircularLinkedListTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
using System;
using DataStructures.LinkedList.CircularLinkedList;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using NUnit.Framework;

namespace DataStructures.Tests.LinkedList;

[TestFixture]
public static class CircularLinkedListTests
{
[Test]
public static void TestDisplay()
{
var cll = new CircularLinkedList<int>();
cll.InsertAtEnd(10);
cll.InsertAtEnd(20);
cll.InsertAtEnd(30);

Assert.That("10 20 30", Is.EqualTo(GetDisplayOutput(cll).Trim()));
}

[Test]
public static void TestDisplayEmptyList()
{
var cll = new CircularLinkedList<int>();
cll.Display();

Assert.That("List is empty.", Is.EqualTo(GetDisplayOutput(cll).Trim()));
}

[Test]
public static void TestInsertAtBeginning()
{
var cll = new CircularLinkedList<int>();
cll.InsertAtBeginning(10);
cll.InsertAtBeginning(20);
cll.InsertAtBeginning(30);

Assert.That("30 20 10", Is.EqualTo(GetDisplayOutput(cll).Trim()));
}

[Test]
public static void TestInsertAtEnd()
{
var cll = new CircularLinkedList<int>();
cll.InsertAtEnd(10);
cll.InsertAtEnd(20);
cll.InsertAtEnd(30);

Assert.That("10 20 30", Is.EqualTo(GetDisplayOutput(cll).Trim()));
}

[Test]
public static void TestInsertAfter()
{
var cll = new CircularLinkedList<int>();
cll.InsertAtEnd(10);
cll.InsertAtEnd(20);
cll.InsertAtEnd(30);

cll.InsertAfter(20, 25);
Assert.That("10 20 25 30", Is.EqualTo(GetDisplayOutput(cll).Trim()));
}

[Test]
public static void TestInsertAtBeginningInEmptyList()
{
var cll = new CircularLinkedList<int>();
cll.InsertAtBeginning(10);
Assert.That("10", Is.EqualTo(GetDisplayOutput(cll).Trim()));
}

[Test]
public static void TestInsertAtEndInEmptyList()
{
var cll = new CircularLinkedList<int>();
cll.InsertAtEnd(10);

Assert.That("10", Is.EqualTo(GetDisplayOutput(cll).Trim()));
}

[Test]
public static void TestInsertAfterInEmptyList()
{
var cll = new CircularLinkedList<int>();
cll.InsertAfter(10, 20);

Assert.That("List is empty.", Is.EqualTo(GetDisplayOutput(cll).Trim()));
}



[Test]
public static void TestInsertAfterSpecificNode()
{
var cll = new CircularLinkedList<int>();
cll.InsertAtEnd(10);
cll.InsertAtEnd(20);
cll.InsertAtEnd(30);

cll.InsertAfter(20, 25); // Insert after node with value 20
Assert.That("10 20 25 30", Is.EqualTo(GetDisplayOutput(cll).Trim()));
}

[Test]
public static void TestInsertAfterOnNonExistingValue()
{
var cll = new CircularLinkedList<int>();
cll.InsertAtEnd(10);
cll.InsertAfter(99, 25); // 99 does not exist
Assert.That("10", Is.EqualTo(GetDisplayOutput(cll).Trim()));
}

[Test]
public static void TestDeleteNode()
{
var cll = new CircularLinkedList<int>();
cll.InsertAtEnd(10);
cll.InsertAtEnd(20);
cll.InsertAtEnd(30);

cll.DeleteNode(20);
Assert.That("10 30", Is.EqualTo(GetDisplayOutput(cll).Trim()));
}

[Test]
public static void TestDeleteOnlyNode()
{
var cll = new CircularLinkedList<int>();
cll.InsertAtBeginning(10);
cll.DeleteNode(10);
Assert.That(cll.IsEmpty(), Is.EqualTo(true));
}

[Test]
public static void TestDeleteHeadNode()
{
var cll = new CircularLinkedList<int>();
cll.InsertAtEnd(10);
cll.InsertAtEnd(20);
cll.InsertAtEnd(30);
cll.DeleteNode(10);
Assert.That("20 30", Is.EqualTo(GetDisplayOutput(cll).Trim()));
}

[Test]
public static void TestDeleteTailNode()
{
var cll = new CircularLinkedList<int>();
cll.InsertAtEnd(10);
cll.InsertAtEnd(20);
cll.InsertAtEnd(30);
cll.DeleteNode(30);
Assert.That("10 20", Is.EqualTo(GetDisplayOutput(cll).Trim()));
}

[Test]
public static void TestDeleteFromEmptyList()
{
var cll = new CircularLinkedList<int>();
cll.DeleteNode(10);
Assert.That(cll.IsEmpty(), Is.EqualTo(true));
}

[Test]
public static void TestDeleteNonExistentNode()
{
var cll = new CircularLinkedList<int>();
cll.InsertAtEnd(10);
cll.InsertAtEnd(20);
cll.InsertAtEnd(30);

cll.DeleteNode(40); // Attempting to delete a node that doesn't exist
Assert.That("10 20 30", Is.EqualTo(GetDisplayOutput(cll).Trim()));
}

/// <summary>
/// Helper method to capture the output of the Display method for assertions.
/// </summary>
/// <param name="list">The CircularLinkedList instance.</param>
/// <returns>A string representation of the list.</returns>
private static string GetDisplayOutput(CircularLinkedList<int> list)
{
// Save the original output (the default Console output stream)
var originalConsoleOut = Console.Out;

// Use a StringWriter to capture Console output
using (var sw = new System.IO.StringWriter())
{
try
{
// Redirect Console output to StringWriter
Console.SetOut(sw);

// Call the method that outputs to the console
list.Display();

// Return the captured output
return sw.ToString();
}
finally
{
// Restore the original Console output stream
Console.SetOut(originalConsoleOut);
}
}
}
}
181 changes: 181 additions & 0 deletions DataStructures/LinkedList/CircularLinkedList/CircularLinkedList.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
using System;

namespace DataStructures.LinkedList.CircularLinkedList
{
/// <summary>
/// CircularLinkedList.
/// @author Mohit Singh. <a href="https://github.com/mohit-gogitter">mohit-gogitter</a>
/// </summary>
/// <typeparam name="T">The generic type parameter.</typeparam>
public class CircularLinkedList<T>
{
/// <summary>
/// Points to the last node in the Circular Linked List.
/// </summary>
private CircularLinkedListNode<T>? tail;

/// <summary>
/// Initializes a new instance of the <see cref="CircularLinkedList{T}"/> class.
/// </summary>
public CircularLinkedList()
{
tail = null;
}

/// <summary>
/// Determines whether the Circular Linked List is empty.
/// </summary>
/// <returns>True if the list is empty; otherwise, false.</returns>
public bool IsEmpty()
{
return tail == null;
}

/// <summary>
/// Inserts a new node at the beginning of the Circular Linked List.
/// </summary>
/// <param name="data">The data to insert into the new node.</param>
public void InsertAtBeginning(T data)
{
var newNode = new CircularLinkedListNode<T>(data);
if (IsEmpty())
{
tail = newNode;
tail.Next = tail;
}
else
{
newNode.Next = tail!.Next;
tail.Next = newNode;
}
}

/// <summary>
/// Inserts a new node at the end of the Circular Linked List.
/// </summary>
/// <param name="data">The data to insert into the new node.</param>
public void InsertAtEnd(T data)
{
var newNode = new CircularLinkedListNode<T>(data);
if (IsEmpty())
{
tail = newNode;
tail.Next = tail;
}
else
{
newNode.Next = tail!.Next;
tail.Next = newNode;
tail = newNode;
}
}

/// <summary>
/// Inserts a new node after a specific value in the list.
/// </summary>
/// <param name="value">The value to insert the node after.</param>
/// <param name="data">The data to insert into the new node.</param>
public void InsertAfter(T value, T data)
{
if (IsEmpty())
{
Console.WriteLine("List is empty.");
return;
}

var current = tail!.Next;
do
{
if (current!.Data!.Equals(value))
{
var newNode = new CircularLinkedListNode<T>(data);
newNode.Next = current.Next;
current.Next = newNode;

if (current == tail)
{
tail = newNode;
}

Check warning on line 98 in DataStructures/LinkedList/CircularLinkedList/CircularLinkedList.cs

View check run for this annotation

Codecov / codecov/patch

DataStructures/LinkedList/CircularLinkedList/CircularLinkedList.cs#L96-L98

Added lines #L96 - L98 were not covered by tests

return;
}

current = current.Next;
}
while (current != tail.Next);

Console.WriteLine($"Node with value {value} not found.");
}

/// <summary>
/// Deletes a node with a specific value from the list.
/// </summary>
/// <param name="value">The value of the node to delete.</param>
public void DeleteNode(T value)
{
if (IsEmpty())
{
Console.WriteLine("List is empty.");
return;
}

var current = tail!.Next;
var previous = tail;

do
{
if (current!.Data!.Equals(value))
{
if (current == tail && current.Next == tail)
{
tail = null;
}
else if (current == tail)
{
previous!.Next = tail.Next;
tail = previous;
}
else if (current == tail.Next)
{
tail.Next = current.Next;
}
else
{
previous!.Next = current.Next;
}

Console.WriteLine($"Node with value {value} deleted.");
return;
}

previous = current;
current = current.Next;
}
while (current != tail!.Next);

Console.WriteLine($"Node with value {value} not found.");
}

/// <summary>
/// Displays the contents of the Circular Linked List.
/// </summary>
public void Display()
{
if (IsEmpty())
{
Console.WriteLine("List is empty.");
return;
}

CircularLinkedListNode<T>? current = tail!.Next;
do
{
Console.Write($"{current!.Data} ");
current = current.Next;
}
while (current != tail!.Next);

Console.WriteLine();
}
}
}
Loading
Loading