Skip to content

Commit

Permalink
Enhance docs, remove main, add tests in NodeStack (#6017)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hardvan authored Oct 26, 2024
1 parent 1e50706 commit ab9a552
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 107 deletions.
1 change: 1 addition & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,7 @@
* [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
* [NodeStackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/stacks/NodeStackTest.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)
Expand Down
162 changes: 55 additions & 107 deletions src/main/java/com/thealgorithms/datastructures/stacks/NodeStack.java
Original file line number Diff line number Diff line change
@@ -1,161 +1,109 @@
package com.thealgorithms.datastructures.stacks;

/**
* Implementation of a stack using nodes. Unlimited size, no arraylist.
* A stack implementation using linked nodes, supporting unlimited size without an ArrayList.
*
* @author Kyler Smith, 2017
* <p>Each node in the stack contains data of generic type {@code Item}, along with references
* to the next and previous nodes, supporting typical stack operations.
*
* <p>The stack follows a Last-In-First-Out (LIFO) order where elements added last are
* removed first. Supported operations include push, pop, and peek.
*
* @param <Item> the type of elements held in this stack
*/
public class NodeStack<Item> {

/**
* Entry point for the program.
* Node class representing each element in the stack.
*/
public static void main(String[] args) {
NodeStack<Integer> stack = new NodeStack<Integer>();

stack.push(3);
stack.push(4);
stack.push(5);
System.out.println("Testing :");
stack.print(); // prints : 5 4 3
private class Node {
Item data;
Node previous;

Integer x = stack.pop(); // x = 5
stack.push(1);
stack.push(8);
Integer y = stack.peek(); // y = 8
System.out.println("Testing :");
stack.print(); // prints : 8 1 4 3

System.out.println("Testing :");
System.out.println("x : " + x);
System.out.println("y : " + y);
Node(Item data) {
this.data = data;
this.previous = null;
}
}

/**
* Information each node should contain.
*
* @value data : information of the value in the node
* @value head : the head of the stack
* @value next : the next value from this node
* @value previous : the last value from this node
* @value size : size of the stack
*/
private Item data;

private static NodeStack<?> head;
private NodeStack<?> previous;
private static int size = 0;
private Node head; // Top node in the stack
private int size; // Number of elements in the stack

/**
* Constructors for the NodeStack.
* Constructs an empty NodeStack.
*/
public NodeStack() {
}

private NodeStack(Item item) {
this.data = item;
head = null;
size = 0;
}

/**
* Put a value onto the stack.
* Pushes an item onto the stack.
*
* @param item : value to be put on the stack.
* @param item the item to be pushed onto the stack
*/
public void push(Item item) {
NodeStack<Item> newNs = new NodeStack<Item>(item);

if (this.isEmpty()) {
NodeStack.setHead(new NodeStack<>(item));
newNs.setNext(null);
newNs.setPrevious(null);
} else {
newNs.setPrevious(NodeStack.head);
NodeStack.head.setNext(newNs);
NodeStack.setHead(newNs);
}

NodeStack.setSize(NodeStack.getSize() + 1);
Node newNode = new Node(item);
newNode.previous = head;
head = newNode;
size++;
}

/**
* Value to be taken off the stack.
* Removes and returns the item at the top of the stack.
*
* @return item : value that is returned.
* @return the item at the top of the stack, or {@code null} if the stack is empty
* @throws IllegalStateException if the stack is empty
*/
public Item pop() {
Item item = (Item) NodeStack.head.getData();

NodeStack.setHead(NodeStack.head.getPrevious());
NodeStack.head.setNext(null);

NodeStack.setSize(NodeStack.getSize() - 1);

return item;
if (isEmpty()) {
throw new IllegalStateException("Cannot pop from an empty stack.");
}
Item data = head.data;
head = head.previous;
size--;
return data;
}

/**
* Value that is next to be taken off the stack.
* Returns the item at the top of the stack without removing it.
*
* @return item : the next value that would be popped off the stack.
* @return the item at the top of the stack, or {@code null} if the stack is empty
* @throws IllegalStateException if the stack is empty
*/
public Item peek() {
return (Item) NodeStack.head.getData();
if (isEmpty()) {
throw new IllegalStateException("Cannot peek from an empty stack.");
}
return head.data;
}

/**
* If the stack is empty or there is a value in.
* Checks whether the stack is empty.
*
* @return boolean : whether or not the stack has anything in it.
* @return {@code true} if the stack has no elements, {@code false} otherwise
*/
public boolean isEmpty() {
return NodeStack.getSize() == 0;
return head == null;
}

/**
* Returns the size of the stack.
* Returns the number of elements currently in the stack.
*
* @return int : number of values in the stack.
* @return the size of the stack
*/
public int size() {
return NodeStack.getSize();
return size;
}

/**
* Print the contents of the stack in the following format.
*
* <p>
* x <- head (next out) y z <- tail (first in) . . .
* Prints the contents of the stack from top to bottom.
*/
public void print() {
for (NodeStack<?> n = NodeStack.head; n != null; n = n.previous) {
System.out.println(n.getData().toString());
Node current = head;
while (current != null) {
System.out.println(current.data);
current = current.previous;
}
}

private static void setHead(NodeStack<?> ns) {
NodeStack.head = ns;
}

private void setNext(NodeStack<?> next) {
}

private NodeStack<?> getPrevious() {
return previous;
}

private void setPrevious(NodeStack<?> previous) {
this.previous = previous;
}

private static int getSize() {
return size;
}

private static void setSize(int size) {
NodeStack.size = size;
}

private Item getData() {
return this.data;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
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.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.Test;

class NodeStackTest {

@Test
void testPush() {
NodeStack<Integer> stack = new NodeStack<>();
stack.push(10);
stack.push(20);
assertEquals(20, stack.peek(), "Top element should be 20 after pushing 10 and 20.");
}

@Test
void testPop() {
NodeStack<String> stack = new NodeStack<>();
stack.push("First");
stack.push("Second");
assertEquals("Second", stack.pop(), "Pop should return 'Second', the last pushed element.");
assertEquals("First", stack.pop(), "Pop should return 'First' after 'Second' is removed.");
}

@Test
void testPopOnEmptyStack() {
NodeStack<Double> stack = new NodeStack<>();
assertThrows(IllegalStateException.class, stack::pop, "Popping an empty stack should throw IllegalStateException.");
}

@Test
void testPeek() {
NodeStack<Integer> stack = new NodeStack<>();
stack.push(5);
stack.push(15);
assertEquals(15, stack.peek(), "Peek should return 15, the top element.");
stack.pop();
assertEquals(5, stack.peek(), "Peek should return 5 after 15 is popped.");
}

@Test
void testPeekOnEmptyStack() {
NodeStack<String> stack = new NodeStack<>();
assertThrows(IllegalStateException.class, stack::peek, "Peeking an empty stack should throw IllegalStateException.");
}

@Test
void testIsEmpty() {
NodeStack<Character> stack = new NodeStack<>();
assertTrue(stack.isEmpty(), "Newly initialized stack should be empty.");
stack.push('A');
assertFalse(stack.isEmpty(), "Stack should not be empty after a push operation.");
stack.pop();
assertTrue(stack.isEmpty(), "Stack should be empty after popping the only element.");
}

@Test
void testSize() {
NodeStack<Integer> stack = new NodeStack<>();
assertEquals(0, stack.size(), "Size of empty stack should be 0.");
stack.push(3);
stack.push(6);
assertEquals(2, stack.size(), "Size should be 2 after pushing two elements.");
stack.pop();
assertEquals(1, stack.size(), "Size should be 1 after popping one element.");
stack.pop();
assertEquals(0, stack.size(), "Size should be 0 after popping all elements.");
}

@Test
void testPrint() {
NodeStack<Integer> stack = new NodeStack<>();
stack.push(1);
stack.push(2);
stack.push(3);

// Output verification would ideally be handled through a different means
// but you can print as a basic check to confirm method runs without errors.
stack.print();
}
}

0 comments on commit ab9a552

Please sign in to comment.