diff --git a/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java
index 2b50f73101fb..422e8953625f 100644
--- a/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java
+++ b/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java
@@ -1,8 +1,23 @@
package com.thealgorithms.datastructures.lists;
+/**
+ * This class is a circular singly linked list implementation. In a circular linked list,
+ * the last node points back to the first node, creating a circular chain.
+ *
+ *
This implementation includes basic operations such as appending elements
+ * to the end, removing elements from a specified position, and converting
+ * the list to a string representation.
+ *
+ * @param the type of elements held in this list
+ */
public class CircleLinkedList {
- private static final class Node {
+ /**
+ * A static nested class representing a node in the circular linked list.
+ *
+ * @param the type of element stored in the node
+ */
+ static final class Node {
Node next;
E value;
@@ -13,44 +28,56 @@ private Node(E value, Node next) {
}
}
- // For better O.O design this should be private allows for better black box design
private int size;
- // this will point to dummy node;
- private Node head = null;
- private Node tail = null; // keeping a tail pointer to keep track of the end of list
+ Node head = null;
+ private Node tail;
- // constructor for class.. here we will make a dummy node for circly linked list implementation
- // with reduced error catching as our list will never be empty;
+ /**
+ * Initializes a new circular linked list. A dummy head node is used for simplicity,
+ * pointing initially to itself to ensure the list is never empty.
+ */
public CircleLinkedList() {
- // creation of the dummy node
- head = new Node(null, head);
+ head = new Node<>(null, head);
tail = head;
size = 0;
}
- // getter for the size... needed because size is private.
+ /**
+ * Returns the current size of the list.
+ *
+ * @return the number of elements in the list
+ */
public int getSize() {
return size;
}
- // for the sake of simplistiy this class will only contain the append function or addLast other
- // add functions can be implemented however this is the basses of them all really.
+ /**
+ * Appends a new element to the end of the list. Throws a NullPointerException if
+ * a null value is provided.
+ *
+ * @param value the value to append to the list
+ * @throws NullPointerException if the value is null
+ */
public void append(E value) {
if (value == null) {
- // we do not want to add null elements to the list.
throw new NullPointerException("Cannot add null element to the list");
}
- // head.next points to the last element;
if (tail == null) {
- tail = new Node(value, head);
+ tail = new Node<>(value, head);
head.next = tail;
} else {
- tail.next = new Node(value, head);
+ tail.next = new Node<>(value, head);
tail = tail.next;
}
size++;
}
+ /**
+ * Returns a string representation of the list in the format "[ element1, element2, ... ]".
+ * An empty list is represented as "[]".
+ *
+ * @return the string representation of the list
+ */
public String toString() {
if (size == 0) {
return "[]";
@@ -68,23 +95,27 @@ public String toString() {
return sb.toString();
}
+ /**
+ * Removes and returns the element at the specified position in the list.
+ * Throws an IndexOutOfBoundsException if the position is invalid.
+ *
+ * @param pos the position of the element to remove
+ * @return the value of the removed element
+ * @throws IndexOutOfBoundsException if the position is out of range
+ */
public E remove(int pos) {
if (pos >= size || pos < 0) {
- // catching errors
- throw new IndexOutOfBoundsException("position cannot be greater than size or negative");
+ throw new IndexOutOfBoundsException("Position out of bounds");
}
- // we need to keep track of the element before the element we want to remove we can see why
- // bellow.
+
Node before = head;
for (int i = 1; i <= pos; i++) {
before = before.next;
}
Node destroy = before.next;
E saved = destroy.value;
- // assigning the next reference to the element following the element we want to remove...
- // the last element will be assigned to the head.
- before.next = before.next.next;
- // scrubbing
+ before.next = destroy.next;
+
if (destroy == tail) {
tail = before;
}
diff --git a/src/test/java/com/thealgorithms/datastructures/lists/CircleLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/CircleLinkedListTest.java
index b7a05ef29d66..883d2b02ba7c 100644
--- a/src/test/java/com/thealgorithms/datastructures/lists/CircleLinkedListTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/lists/CircleLinkedListTest.java
@@ -1,78 +1,115 @@
package com.thealgorithms.datastructures.lists;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class CircleLinkedListTest {
+ private CircleLinkedList list;
+
+ @BeforeEach
+ public void setUp() {
+ list = new CircleLinkedList<>();
+ }
+
+ @Test
+ public void testInitialSize() {
+ assertEquals(0, list.getSize(), "Initial size should be 0.");
+ }
+
@Test
public void testAppendAndSize() {
- CircleLinkedList list = new CircleLinkedList<>();
list.append(1);
list.append(2);
list.append(3);
- assertEquals(3, list.getSize());
- assertEquals("[ 1, 2, 3 ]", list.toString());
+ assertEquals(3, list.getSize(), "Size after three appends should be 3.");
+ assertEquals("[ 1, 2, 3 ]", list.toString(), "List content should match appended values.");
}
@Test
public void testRemove() {
- CircleLinkedList list = new CircleLinkedList<>();
list.append(1);
list.append(2);
list.append(3);
list.append(4);
- assertEquals(2, list.remove(1));
- assertEquals(3, list.remove(1));
- assertEquals("[ 1, 4 ]", list.toString());
- assertEquals(2, list.getSize());
+ assertEquals(2, list.remove(1), "Removed element at index 1 should be 2.");
+ assertEquals(3, list.remove(1), "Removed element at index 1 after update should be 3.");
+ assertEquals("[ 1, 4 ]", list.toString(), "List content should reflect removals.");
+ assertEquals(2, list.getSize(), "Size after two removals should be 2.");
}
@Test
public void testRemoveInvalidIndex() {
- CircleLinkedList list = new CircleLinkedList<>();
list.append(1);
list.append(2);
- assertThrows(IndexOutOfBoundsException.class, () -> list.remove(2));
- assertThrows(IndexOutOfBoundsException.class, () -> list.remove(-1));
+ assertThrows(IndexOutOfBoundsException.class, () -> list.remove(2), "Should throw on out-of-bounds index.");
+ assertThrows(IndexOutOfBoundsException.class, () -> list.remove(-1), "Should throw on negative index.");
}
@Test
public void testToStringEmpty() {
- CircleLinkedList list = new CircleLinkedList<>();
- assertEquals("[]", list.toString());
+ assertEquals("[]", list.toString(), "Empty list should be represented by '[]'.");
}
@Test
public void testToStringAfterRemoval() {
- CircleLinkedList list = new CircleLinkedList<>();
list.append(1);
list.append(2);
list.append(3);
list.remove(1);
- assertEquals("[ 1, 3 ]", list.toString());
+ assertEquals("[ 1, 3 ]", list.toString(), "List content should match remaining elements after removal.");
}
@Test
public void testSingleElement() {
- CircleLinkedList list = new CircleLinkedList<>();
list.append(1);
- assertEquals(1, list.getSize());
- assertEquals("[ 1 ]", list.toString());
- assertEquals(1, list.remove(0));
- assertEquals("[]", list.toString());
+ assertEquals(1, list.getSize(), "Size after single append should be 1.");
+ assertEquals("[ 1 ]", list.toString(), "Single element list should display properly.");
+ assertEquals(1, list.remove(0), "Single element removed should match appended value.");
+ assertEquals("[]", list.toString(), "List should be empty after removing the single element.");
}
@Test
public void testNullElement() {
- CircleLinkedList list = new CircleLinkedList<>();
- assertThrows(NullPointerException.class, () -> list.append(null));
+ assertThrows(NullPointerException.class, () -> list.append(null), "Appending null should throw exception.");
+ }
+
+ @Test
+ public void testCircularReference() {
+ list.append(1);
+ list.append(2);
+ list.append(3);
+ CircleLinkedList.Node current = list.head;
+
+ // Traverse one full cycle and verify the circular reference
+ for (int i = 0; i <= list.getSize(); i++) {
+ current = current.next;
+ }
+ assertEquals(list.head, current, "End of list should point back to the head (circular structure).");
+ }
+
+ @Test
+ public void testClear() {
+ list.append(1);
+ list.append(2);
+ list.append(3);
+
+ // Remove all elements to simulate clearing the list
+ for (int i = list.getSize() - 1; i >= 0; i--) {
+ list.remove(i);
+ }
+
+ assertEquals(0, list.getSize(), "Size after clearing should be 0.");
+ assertEquals("[]", list.toString(), "Empty list should be represented by '[]' after clear.");
+ assertSame(list.head.next, list.head, "Head's next should point to itself after clearing.");
}
}