diff --git a/DIRECTORY.md b/DIRECTORY.md index 98fbec625..2a6bf70c7 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -571,6 +571,7 @@ * [UnionFind](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/UnionFind.java) * [UpperBound](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/UpperBound.java) * slidingwindow + * [LongestSubstringWithoutRepeatingCharacters](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/slidingwindow/LongestSubstringWithoutRepeatingCharacters.java) * [MaxSumKSizeSubarray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/slidingwindow/MaxSumKSizeSubarray.java) * sorts * [AdaptiveMergeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/AdaptiveMergeSort.java) @@ -855,9 +856,9 @@ * [QueueByTwoStacksTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/QueueByTwoStacksTest.java) * [QueueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/QueueTest.java) * stacks - * [LinkedListStackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/stacks/LinkedListStackTest.java) * [StackArrayListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/stacks/StackArrayListTest.java) * [StackArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/stacks/StackArrayTest.java) + * [StackOfLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/stacks/StackOfLinkedListTest.java) * trees * [BinaryTreeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeTest.java) * [BoundaryTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java) @@ -1163,6 +1164,7 @@ * [UnionFindTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/UnionFindTest.java) * [UpperBoundTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/UpperBoundTest.java) * slidingwindow + * [LongestSubstringWithoutRepeatingCharactersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/slidingwindow/LongestSubstringWithoutRepeatingCharactersTest.java) * [MaxSumKSizeSubarrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/slidingwindow/MaxSumKSizeSubarrayTest.java) * sorts * [AdaptiveMergeSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/AdaptiveMergeSortTest.java) diff --git a/src/main/java/com/thealgorithms/datastructures/stacks/StackOfLinkedList.java b/src/main/java/com/thealgorithms/datastructures/stacks/StackOfLinkedList.java index 52b1c1d86..c12097dfa 100644 --- a/src/main/java/com/thealgorithms/datastructures/stacks/StackOfLinkedList.java +++ b/src/main/java/com/thealgorithms/datastructures/stacks/StackOfLinkedList.java @@ -3,35 +3,20 @@ package com.thealgorithms.datastructures.stacks; import java.util.NoSuchElementException; /** - * @author Varun Upadhyay (https://github.com/varunu28) + * A stack implementation using a singly linked list. + * + *

This class provides methods to push, pop, and peek elements in a Last-In-First-Out (LIFO) manner. + * It keeps track of the number of elements in the stack and allows checking if the stack is empty. + * + *

This implementation does not allow null elements to be pushed onto the stack. */ -// An implementation of a Stack using a Linked List final class StackOfLinkedList { private StackOfLinkedList() { } - - public static void main(String[] args) { - LinkedListStack stack = new LinkedListStack(); - stack.push(1); - stack.push(2); - stack.push(3); - stack.push(4); - stack.push(5); - - System.out.println(stack); - - System.out.println("Size of stack currently is: " + stack.getSize()); - - assert stack.pop() == 5; - assert stack.pop() == 4; - - System.out.println("Top element of stack currently is: " + stack.peek()); - } } -// A node class +// A node class for the linked list class Node { - public int data; public Node next; @@ -42,25 +27,24 @@ class Node { } /** - * A class which implements a stack using a linked list + * A class that implements a stack using a linked list. * - *

- * Contains all the stack methods : push, pop, printStack, isEmpty + *

This stack supports basic operations: + *

*/ class LinkedListStack { - /** - * Top of stack - */ - Node head; + private Node head; // Top of the stack + private int size; // Number of elements in the stack /** - * Size of stack - */ - private int size; - - /** - * Init properties + * Initializes an empty stack. */ LinkedListStack() { head = null; @@ -68,10 +52,10 @@ class LinkedListStack { } /** - * Add element at top + * Adds an element to the top of the stack. * - * @param x to be added - * @return true if add successfully + * @param x the element to be added + * @return true if the element is added successfully */ public boolean push(int x) { Node newNode = new Node(x); @@ -82,10 +66,10 @@ class LinkedListStack { } /** - * Pop element at top of stack + * Removes and returns the top element of the stack. * - * @return element at top of stack - * @throws NoSuchElementException if stack is empty + * @return the element at the top of the stack + * @throws NoSuchElementException if the stack is empty */ public int pop() { if (size == 0) { @@ -94,20 +78,20 @@ class LinkedListStack { Node destroy = head; head = head.next; int retValue = destroy.data; - destroy = null; // clear to let GC do it's work + destroy = null; // Help garbage collection size--; return retValue; } /** - * Peek element at top of stack + * Returns the top element of the stack without removing it. * - * @return element at top of stack - * @throws NoSuchElementException if stack is empty + * @return the element at the top of the stack + * @throws NoSuchElementException if the stack is empty */ public int peek() { if (size == 0) { - throw new NoSuchElementException("Empty stack. Nothing to pop"); + throw new NoSuchElementException("Empty stack. Nothing to peek"); } return head.data; } @@ -120,24 +104,32 @@ class LinkedListStack { builder.append(cur.data).append("->"); cur = cur.next; } - return builder.replace(builder.length() - 2, builder.length(), "").toString(); + return builder.replace(builder.length() - 2, builder.length(), "").toString(); // Remove the last "->" } /** - * Check if stack is empty + * Checks if the stack is empty. * - * @return true if stack is empty, otherwise false + * @return true if the stack is empty, false otherwise */ public boolean isEmpty() { return size == 0; } /** - * Return size of stack + * Returns the current size of the stack. * - * @return size of stack + * @return the number of elements in the stack */ public int getSize() { return size; } + + /** + * Removes all elements from the stack. + */ + public void makeEmpty() { + head = null; + size = 0; + } } diff --git a/src/test/java/com/thealgorithms/datastructures/stacks/LinkedListStackTest.java b/src/test/java/com/thealgorithms/datastructures/stacks/LinkedListStackTest.java deleted file mode 100644 index 8c3689a79..000000000 --- a/src/test/java/com/thealgorithms/datastructures/stacks/LinkedListStackTest.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.thealgorithms.datastructures.stacks; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.NoSuchElementException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class LinkedListStackTest { - - private LinkedListStack stack; - - @BeforeEach - public void setUp() { - stack = new LinkedListStack(); - } - - @Test - public void testPushAndPeek() { - stack.push(1); - stack.push(2); - stack.push(3); - - assertEquals(3, stack.peek()); - assertEquals(3, stack.getSize()); - } - - @Test - public void testPop() { - stack.push(1); - stack.push(2); - stack.push(3); - - assertEquals(3, stack.pop()); - assertEquals(2, stack.pop()); - assertEquals(1, stack.pop()); - assertTrue(stack.isEmpty()); - } - - @Test - public void testPopEmptyStack() { - org.junit.jupiter.api.Assertions.assertThrows(NoSuchElementException.class, () -> stack.pop()); - } - - @Test - public void testPeekEmptyStack() { - org.junit.jupiter.api.Assertions.assertThrows(NoSuchElementException.class, () -> stack.peek()); - } - - @Test - public void testIsEmpty() { - assertTrue(stack.isEmpty()); - - stack.push(1); - assertFalse(stack.isEmpty()); - - stack.pop(); - assertTrue(stack.isEmpty()); - } - - @Test - public void testToString() { - stack.push(1); - stack.push(2); - stack.push(3); - - assertEquals("3->2->1", stack.toString()); - } -} diff --git a/src/test/java/com/thealgorithms/datastructures/stacks/StackOfLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/stacks/StackOfLinkedListTest.java new file mode 100644 index 000000000..58af66bc3 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/stacks/StackOfLinkedListTest.java @@ -0,0 +1,121 @@ +package com.thealgorithms.datastructures.stacks; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.NoSuchElementException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class StackOfLinkedListTest { + + private LinkedListStack stack; + + @BeforeEach + public void setUp() { + stack = new LinkedListStack(); + } + + @Test + public void testPushAndPeek() { + stack.push(1); + stack.push(2); + stack.push(3); + + assertEquals(3, stack.peek(), "Peek should return the last pushed value"); + assertEquals(3, stack.getSize(), "Size should reflect the number of elements"); + } + + @Test + public void testPop() { + stack.push(1); + stack.push(2); + stack.push(3); + + assertEquals(3, stack.pop(), "Pop should return the last pushed value"); + assertEquals(2, stack.pop(), "Pop should return the next last pushed value"); + assertEquals(1, stack.pop(), "Pop should return the first pushed value"); + assertTrue(stack.isEmpty(), "Stack should be empty after popping all elements"); + } + + @Test + public void testPopEmptyStack() { + org.junit.jupiter.api.Assertions.assertThrows(NoSuchElementException.class, () -> stack.pop(), "Popping from an empty stack should throw NoSuchElementException"); + } + + @Test + public void testPeekEmptyStack() { + org.junit.jupiter.api.Assertions.assertThrows(NoSuchElementException.class, () -> stack.peek(), "Peeking into an empty stack should throw NoSuchElementException"); + } + + @Test + public void testIsEmpty() { + assertTrue(stack.isEmpty(), "Newly created stack should be empty"); + + stack.push(1); + assertFalse(stack.isEmpty(), "Stack should not be empty after pushing an element"); + + stack.pop(); + assertTrue(stack.isEmpty(), "Stack should be empty after popping the only element"); + } + + @Test + public void testToString() { + stack.push(1); + stack.push(2); + stack.push(3); + + assertEquals("3->2->1", stack.toString(), "String representation of stack should match the expected format"); + } + + @Test + public void testMultiplePushesAndPops() { + stack.push(5); + stack.push(10); + stack.push(15); + + assertEquals(15, stack.pop(), "Pop should return the last pushed value"); + assertEquals(10, stack.peek(), "Peek should return the new top value after popping"); + assertEquals(10, stack.pop(), "Pop should return the next last pushed value"); + assertEquals(5, stack.pop(), "Pop should return the first pushed value"); + assertTrue(stack.isEmpty(), "Stack should be empty after popping all elements"); + } + + @Test + public void testGetSize() { + assertEquals(0, stack.getSize(), "Size of an empty stack should be zero"); + stack.push(1); + stack.push(2); + assertEquals(2, stack.getSize(), "Size should reflect the number of elements"); + stack.pop(); + assertEquals(1, stack.getSize(), "Size should decrease with each pop"); + } + + @Test + public void testSizeAfterClearingStack() { + stack.push(1); + stack.push(2); + stack.push(3); + + // Manually clear the stack + while (!stack.isEmpty()) { + stack.pop(); + } + assertTrue(stack.isEmpty(), "Stack should be empty after clearing"); + assertEquals(0, stack.getSize(), "Size should be zero after clearing the stack"); + } + + @Test + public void testSequentialPushAndPop() { + for (int i = 1; i <= 100; i++) { + stack.push(i); + } + assertEquals(100, stack.getSize(), "Size should be 100 after pushing 100 elements"); + + for (int i = 100; i >= 1; i--) { + assertEquals(i, stack.pop(), "Popping should return values in LIFO order"); + } + assertTrue(stack.isEmpty(), "Stack should be empty after popping all elements"); + } +}