Skip to content

Commit 6cbd0ef

Browse files
Array Implementation for Stack
1 parent af1390a commit 6cbd0ef

File tree

4 files changed

+301
-0
lines changed

4 files changed

+301
-0
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package stack.implementation;
2+
3+
import java.util.EmptyStackException;
4+
5+
/**
6+
* An implementation of a fixed-size stack data structure using an array.
7+
*
8+
* <p>This class provides the fundamental stack operations (push, pop, peek)
9+
* and follows the Last-In, First-Out (LIFO) principle. Once created, the
10+
* capacity of the stack cannot be changed.
11+
*/
12+
public class Array {
13+
14+
private final int[] arr;
15+
private int top;
16+
17+
/**
18+
* Constructs a new stack with the specified maximum size.
19+
*
20+
* <p><b>Complexity:</b>
21+
* <ul>
22+
* <li>Time: O(N) where N is the size, due to array allocation.
23+
* <li>Space: O(N) to store the stack elements.
24+
* </ul>
25+
*
26+
* @param size The maximum number of elements the stack can hold.
27+
*/
28+
public Array(int size) {
29+
arr = new int[size];
30+
top = -1;
31+
}
32+
33+
/**
34+
* Pushes an element onto the top of this stack.
35+
*
36+
* <p><b>Complexity:</b> O(1) time and O(1) space.
37+
*
38+
* @param value The element to be pushed onto the stack.
39+
* @throws StackOverflowError if the stack is full.
40+
*/
41+
public void push(int value) {
42+
if (isFull()) {
43+
throw new StackOverflowError("Stack is full. Cannot push element.");
44+
}
45+
arr[++top] = value;
46+
}
47+
48+
/**
49+
* Removes the element at the top of this stack and returns that element.
50+
*
51+
* <p><b>Complexity:</b> O(1) time and O(1) space.
52+
*
53+
* @return The element at the top of this stack.
54+
* @throws EmptyStackException if this stack is empty.
55+
*/
56+
public int pop() {
57+
if (isEmpty()) {
58+
throw new EmptyStackException();
59+
}
60+
// The element is not actually removed, just made inaccessible.
61+
// The next push will overwrite it.
62+
return arr[top--];
63+
}
64+
65+
/**
66+
* Looks at the element at the top of this stack without removing it.
67+
*
68+
* <p><b>Complexity:</b> O(1) time and O(1) space.
69+
*
70+
* @return The element at the top of this stack.
71+
* @throws EmptyStackException if this stack is empty.
72+
*/
73+
public int peek() {
74+
if (isEmpty()) {
75+
throw new EmptyStackException();
76+
}
77+
return arr[top];
78+
}
79+
80+
/**
81+
* Tests if this stack is empty.
82+
*
83+
* <p><b>Complexity:</b> O(1) time and O(1) space.
84+
*
85+
* @return {@code true} if and only if this stack contains no items;
86+
* {@code false} otherwise.
87+
*/
88+
public boolean isEmpty() {
89+
return top == -1;
90+
}
91+
92+
/**
93+
* Tests if this stack is full.
94+
*
95+
* <p><b>Complexity:</b> O(1) time and O(1) space.
96+
*
97+
* @return {@code true} if the stack has reached its maximum capacity;
98+
* {@code false} otherwise.
99+
*/
100+
public boolean isFull() {
101+
return top == arr.length - 1;
102+
}
103+
104+
/**
105+
* Returns the number of elements in this stack.
106+
*
107+
* <p><b>Complexity:</b> O(1) time and O(1) space.
108+
*
109+
* @return The number of elements currently in the stack.
110+
*/
111+
public int size() {
112+
return top + 1;
113+
}
114+
115+
/**
116+
* Displays the contents of the stack from top to bottom.
117+
* This method is primarily for debugging purposes.
118+
*
119+
* <p><b>Complexity:</b> O(N) time, where N is the current number of elements
120+
* in the stack. O(1) space.
121+
*/
122+
public void display() {
123+
System.out.print("Stack (top to bottom): [ ");
124+
for (int i = top; i >= 0; i--) {
125+
System.out.print(arr[i] + " ");
126+
}
127+
System.out.println("]");
128+
}
129+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Provides concrete implementations of the Stack data structure.
3+
*
4+
* <p>This package contains various classes that implement the stack concept,
5+
* each using a different underlying data structure (e.g., arrays, linked lists).
6+
* These classes contain the core logic for stack operations like push, pop, and peek.
7+
*
8+
* @version 2.0
9+
* @since 2.0
10+
*/
11+
package stack.implementation;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Provides implementations of the Stack data structure, a fundamental linear
3+
* data structure that follows the Last-In, First-Out (LIFO) principle.
4+
*
5+
* <p>In a stack, the last element added to the collection is the first one to be
6+
* removed. This package contains various implementations, such as array-based
7+
* or linked-list-based stacks, demonstrating different approaches to this
8+
* classic data structure.
9+
*
10+
* @version 2.0
11+
* @since 2.0
12+
*/
13+
package stack;
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package stack.implementation;
2+
3+
import org.junit.jupiter.api.AfterEach;
4+
import org.junit.jupiter.api.BeforeEach;
5+
import org.junit.jupiter.api.DisplayName;
6+
import org.junit.jupiter.api.Test;
7+
8+
import java.io.ByteArrayOutputStream;
9+
import java.io.PrintStream;
10+
import java.util.EmptyStackException;
11+
12+
import static org.junit.jupiter.api.Assertions.*;
13+
14+
15+
class ArrayTest {
16+
17+
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
18+
private final PrintStream originalOut = System.out;
19+
20+
private Array stack;
21+
22+
@BeforeEach
23+
void setUp() {
24+
// Create a new stack with a capacity of 5 before each test
25+
stack = new Array(5);
26+
// Redirect System.out to our stream capture
27+
System.setOut(new PrintStream(outContent));
28+
}
29+
30+
@AfterEach
31+
void tearDown() {
32+
// Restore the original System.out stream
33+
System.setOut(originalOut);
34+
}
35+
36+
@Test
37+
@DisplayName("A new stack should be empty")
38+
void newStackIsEmpty() {
39+
assertTrue(stack.isEmpty(), "A newly created stack should be empty.");
40+
assertEquals(0, stack.size(), "A newly created stack should have a size of 0.");
41+
assertFalse(stack.isFull(), "A newly created stack should not be full.");
42+
}
43+
44+
@Test
45+
@DisplayName("Pushing an element should increase size and allow peeking")
46+
void pushAndPeek() {
47+
stack.push(10);
48+
assertFalse(stack.isEmpty());
49+
assertEquals(1, stack.size());
50+
assertEquals(10, stack.peek(), "Peek should return the last element pushed.");
51+
52+
stack.push(20);
53+
assertEquals(2, stack.size());
54+
assertEquals(20, stack.peek(), "Peek should be updated after a new push.");
55+
}
56+
57+
@Test
58+
@DisplayName("Popping an element should return it and decrease size (LIFO)")
59+
void popFollowsLifo() {
60+
stack.push(10);
61+
stack.push(20);
62+
stack.push(30);
63+
64+
assertEquals(3, stack.size());
65+
66+
assertEquals(30, stack.pop(), "Pop should return the last element added (30).");
67+
assertEquals(2, stack.size(), "Size should decrease after pop.");
68+
69+
assertEquals(20, stack.pop(), "Pop should return the next element (20).");
70+
assertEquals(1, stack.size());
71+
72+
assertEquals(10, stack.pop(), "Pop should return the final element (10).");
73+
assertEquals(0, stack.size());
74+
assertTrue(stack.isEmpty(), "Stack should be empty after all elements are popped.");
75+
}
76+
77+
@Test
78+
@DisplayName("Peeking into an empty stack should throw EmptyStackException")
79+
void peekOnEmptyStackThrowsException() {
80+
assertTrue(stack.isEmpty());
81+
assertThrows(EmptyStackException.class, () -> stack.peek(), "Peeking into an empty stack must throw EmptyStackException.");
82+
}
83+
84+
@Test
85+
@DisplayName("Popping from an empty stack should throw EmptyStackException")
86+
void popOnEmptyStackThrowsException() {
87+
assertTrue(stack.isEmpty());
88+
assertThrows(EmptyStackException.class, () -> stack.pop(), "Popping from an empty stack must throw EmptyStackException.");
89+
}
90+
91+
@Test
92+
@DisplayName("Pushing to a full stack should throw StackOverflowError")
93+
void pushOnFullStackThrowsException() {
94+
// Fill the stack to its capacity
95+
stack.push(1);
96+
stack.push(2);
97+
stack.push(3);
98+
stack.push(4);
99+
stack.push(5);
100+
101+
assertTrue(stack.isFull(), "Stack should be full after pushing 5 elements.");
102+
assertEquals(5, stack.size());
103+
104+
// Assert that the next push throws the expected error
105+
assertThrows(StackOverflowError.class, () -> stack.push(6), "Pushing to a full stack must throw StackOverflowError.");
106+
}
107+
108+
@Test
109+
@DisplayName("isFull should be true only at maximum capacity")
110+
void isFull() {
111+
Array smallStack = new Array(2);
112+
assertFalse(smallStack.isFull());
113+
114+
smallStack.push(1);
115+
assertFalse(smallStack.isFull());
116+
117+
smallStack.push(2);
118+
assertTrue(smallStack.isFull());
119+
}
120+
121+
@Test
122+
@DisplayName("Constructor with negative capacity should throw NegativeArraySizeException")
123+
void constructorWithNegativeCapacityThrowsException() {
124+
assertThrows(NegativeArraySizeException.class, () -> new Array(-1), "Constructor should not allow a negative size.");
125+
}
126+
127+
@Test
128+
@DisplayName("display() on an empty stack should print correctly")
129+
void displayOnEmptyStack() {
130+
stack.display();
131+
String expectedOutput = "Stack (top to bottom): [ ]" + System.lineSeparator();
132+
assertEquals(expectedOutput, outContent.toString());
133+
}
134+
135+
@Test
136+
@DisplayName("display() on a populated stack should print elements top-to-bottom")
137+
void displayOnPopulatedStack() {
138+
stack.push(10);
139+
stack.push(20);
140+
stack.push(30);
141+
142+
stack.display();
143+
144+
// Note the LIFO order in the output (30 is on top)
145+
String expectedOutput = "Stack (top to bottom): [ 30 20 10 ]" + System.lineSeparator();
146+
assertEquals(expectedOutput, outContent.toString());
147+
}
148+
}

0 commit comments

Comments
 (0)