diff --git a/2-0-data-structures-and-algorithms/src/main/java/com/bobocode/stack/LinkedStack.java b/2-0-data-structures-and-algorithms/src/main/java/com/bobocode/stack/LinkedStack.java index 3f55d096e..c4b6f49c5 100644 --- a/2-0-data-structures-and-algorithms/src/main/java/com/bobocode/stack/LinkedStack.java +++ b/2-0-data-structures-and-algorithms/src/main/java/com/bobocode/stack/LinkedStack.java @@ -1,7 +1,9 @@ package com.bobocode.stack; import com.bobocode.stack.exception.EmptyStackException; -import com.bobocode.util.ExerciseNotCompletedException; + +import java.util.Objects; +import java.util.stream.Stream; /** * {@link LinkedStack} represents a last-in-first-out (LIFO) stack of objects that is based on singly linked generic nodes. @@ -10,6 +12,21 @@ * @param generic type parameter */ public class LinkedStack implements Stack { + private static class Node { + T element; + Node next; + + public static Node valueOf(T element) { + return new Node<>(element); + } + + private Node(T element) { + this.element = element; + } + } + + private Node head; + private int size = 0; /** * This method creates a stack of provided elements @@ -19,7 +36,9 @@ public class LinkedStack implements Stack { * @return a new stack of elements that were passed as method parameters */ public static LinkedStack of(T... elements) { - throw new ExerciseNotCompletedException(); // todo: implement this method + LinkedStack linkedStack = new LinkedStack<>(); + Stream.of(elements).forEach(linkedStack::push); + return linkedStack; } /** @@ -30,7 +49,13 @@ public static LinkedStack of(T... elements) { */ @Override public void push(T element) { - throw new ExerciseNotCompletedException(); // todo: implement this method + Objects.requireNonNull(element); + Node newNode = Node.valueOf(element); + if (head != null) { + newNode.next = head; + } + head = newNode; + size++; } /** @@ -42,7 +67,18 @@ public void push(T element) { */ @Override public T pop() { - throw new ExerciseNotCompletedException(); // todo: implement this method + if (head != null) { + size--; + return retrieveHead(); + } else { + throw new EmptyStackException(); + } + } + + private T retrieveHead() { + T element = head.element; + this.head = head.next; + return element; } /** @@ -52,7 +88,7 @@ public T pop() { */ @Override public int size() { - throw new ExerciseNotCompletedException(); // todo: implement this method + return size; } /** @@ -62,6 +98,6 @@ public int size() { */ @Override public boolean isEmpty() { - throw new ExerciseNotCompletedException(); // todo: implement this method; + return head == null; } } diff --git a/6-0-test-driven-development/src/main/java/com/bobocode/stack/EmptyStackException.java b/6-0-test-driven-development/src/main/java/com/bobocode/stack/EmptyStackException.java new file mode 100644 index 000000000..68b78a2f1 --- /dev/null +++ b/6-0-test-driven-development/src/main/java/com/bobocode/stack/EmptyStackException.java @@ -0,0 +1,5 @@ +package com.bobocode.stack; + +public class EmptyStackException extends RuntimeException{ + +} diff --git a/6-0-test-driven-development/src/main/java/com/bobocode/stack/LinkedStack.java b/6-0-test-driven-development/src/main/java/com/bobocode/stack/LinkedStack.java new file mode 100644 index 000000000..a710d3306 --- /dev/null +++ b/6-0-test-driven-development/src/main/java/com/bobocode/stack/LinkedStack.java @@ -0,0 +1,101 @@ +package com.bobocode.stack; + +import java.util.Objects; +import java.util.stream.Stream; + +/** + * {@link LinkedStack} represents a last-in-first-out (LIFO) stack of objects that is based on singly linked generic nodes. + * A node is implemented as inner static class {@link Node}. + * + * @param generic type parameter + */ +public class LinkedStack implements Stack { + private static class Node { + T element; + Node next; + + public static Node valueOf(T element) { + return new Node<>(element); + } + + private Node(T element) { + this.element = element; + } + } + + private Node head; + private int size = 0; + + /** + * This method creates a stack of provided elements + * + * @param elements elements to add + * @param generic type + * @return a new stack of elements that were passed as method parameters + */ + public static LinkedStack of(T... elements) { + LinkedStack linkedStack = new LinkedStack<>(); + Stream.of(elements).forEach(linkedStack::push); + return linkedStack; + } + + /** + * The method pushes an element onto the top of this stack. This has exactly the same effect as: + * addElement(item) + * + * @param element elements to add + */ + @Override + public void push(T element) { + Objects.requireNonNull(element); + Node newNode = Node.valueOf(element); + if (head != null) { + newNode.next = head; + } + head = newNode; + size++; + } + + /** + * This method removes the object at the top of this stack + * and returns that object as the value of this function. + * + * @return The object at the top of this stack + * @throws EmptyStackException - if this stack is empty + */ + @Override + public T pop() { + if (head != null) { + size--; + return retrieveHead(); + } else { + throw new EmptyStackException(); + } + } + + private T retrieveHead() { + T element = head.element; + this.head = head.next; + return element; + } + + /** + * Returns the number of elements in the stack + * + * @return number of elements + */ + @Override + public int size() { + return size; + } + + /** + * Checks if a stack is empty + * + * @return {@code true} if a stack is empty, {@code false} otherwise + */ + @Override + public boolean isEmpty() { + return head == null; + } +} diff --git a/6-0-test-driven-development/src/test/java/com/bobocode/stack/StackTest.java b/6-0-test-driven-development/src/test/java/com/bobocode/stack/StackTest.java index ca2774b0e..cb6c06f8c 100644 --- a/6-0-test-driven-development/src/test/java/com/bobocode/stack/StackTest.java +++ b/6-0-test-driven-development/src/test/java/com/bobocode/stack/StackTest.java @@ -1,4 +1,75 @@ package com.bobocode.stack; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + public class StackTest { + + private Stack intStack = new LinkedStack<>(); + + @Test + void pushAndPopElementOntoEmptyStack() { + intStack.push(243); + + assertThat(intStack.pop()).isEqualTo(243); + } + + @Test + void popElementFromEmptyStack() { + assertThrows(EmptyStackException.class, () -> intStack.pop()); + } + + @Test + void pushElements() { + intStack = LinkedStack.of(23, 35, 72); + + intStack.push(55); + + assertThat(intStack.pop()).isEqualTo(55); + } + + @Test + void popElements() { + intStack = LinkedStack.of(87, 53, 66); + + intStack.pop(); + intStack.push(234); + Integer lastElement = intStack.pop(); + + assertThat(lastElement).isEqualTo(234); + } + + @Test + void size() { + intStack = LinkedStack.of(87, 53, 66); + + int actualSize = intStack.size(); + + assertThat(actualSize).isEqualTo(3); + } + + @Test + void sizeOnEmptyStack() { + int actualSize = intStack.size(); + + assertThat(actualSize).isEqualTo(0); + } + + @Test + void isEmpty() { + intStack = LinkedStack.of(87, 53, 66); + + boolean stackEmpty = intStack.isEmpty(); + + assertThat(stackEmpty).isEqualTo(false); + } + + @Test + void isEmptyOnEmptyStack() { + boolean stackEmpty = intStack.isEmpty(); + + assertThat(stackEmpty).isEqualTo(true); + } }