-
Notifications
You must be signed in to change notification settings - Fork 19.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
141 additions
and
107 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
162 changes: 55 additions & 107 deletions
162
src/main/java/com/thealgorithms/datastructures/stacks/NodeStack.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
85 changes: 85 additions & 0 deletions
85
src/test/java/com/thealgorithms/datastructures/stacks/NodeStackTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} |