A stack is a simple data idea that many people use every day without thinking. Think about a pile of plates in your kitchen. You put a new plate on the top. When you need a plate, you take the top plate first. This is how a stack works. In a stack, the last thing you put in is the first thing you take out. People call this rule LIFO, which means Last In, First Out. Stacks are used in apps, in phones, and in big programs too. They help with undo buttons, back buttons in a web browser, checking brackets in code, and many more jobs. In this article, we will learn what a stack is, why it is useful, what actions it can do, how fast it is, and how to build it in Java. We will also look at easy steps, small code parts, and clear lists. We will use very simple words. We will keep ideas slow and friendly. If you are new to coding, do not worry. You will still follow fine. By the end, you will be able to explain stacks to a friend and write your own stack code with confidence.
Stack: Simple Guide
This section is for readers who want the main idea fast. It gives the whole crust of the article in a short and clear way. You can read this first if you do not want to go deep right now. It tells you what a stack is, how it works, why it is useful, and what the main actions are. It also points to how fast each action is, and where stacks are used in real life and in code. If you later want more detail, you can jump to the deeper parts below. But if you only have a few minutes, this quick part will still give you value. It uses simple words and short points. It tries to remove fear. It helps you remember the key words like LIFO, push, pop, and peek. It also tells you common mistakes to avoid, like stack overflow and stack underflow. Read on for the fast take.
Quick crust of the article
- Stack = a list where you add and remove only at the top. Rule: LIFO (Last In, First Out).
- Main actions: push (add on top), pop (remove top), peek (look at top), isEmpty, size.
- Real life: plates pile, undo in editors, browser back, call stack in programs, bracket matching.
- Why use: simple, fast top work, easy to reason, safe order.
- Watch out: overflow if full (fixed size), underflow if empty and you pop.
- Speed: push/pop/peek are usually O(1). Search is O(n).
- Build it: use an array or a linked list. Both work well.
- Good habits: check empty before pop or peek, handle errors, test step by step.
- Best uses: undo/redo, parsing, backtracking, DFS, function calls, expression eval.
Now we will explain what a stack really is in simple words. We will start from the idea, then we will show steps. We will use friendly examples. We will also compare it to daily life. The goal is that you can explain it to a friend with no code. Then we will add code after you feel safe with the idea. If you remember only one thing, remember this: a stack is like a pile where you only touch the top. If you put it last, you take it first. That is the heart of it. This simple rule gives a lot of power. It keeps order and makes some jobs very easy. Many tools you use today depend on this simple rule, even if you do not see it.
What is a stack
A stack is a special list where you can only add a new item to the top and take an item from the top. You do not insert in the middle. You do not remove from the bottom. You always use the top. This makes the rule very clear and simple. Because of this rule, the order is always LIFO. The last thing you add is the first thing you remove. Think of a stack like a tower of blocks. You put one block on top of another. When you remove a block, you take the top block. You do not try to pull a block out from the middle, because the tower would fall. In the same way, a stack keeps things stable and simple by only using the top. This design is not only easy to understand. It also makes many actions very fast, because you do not search through the list. You just work at one end. A stack can be built in many ways in code, like with an array or a linked list. But the rule stays the same in all cases. This simple rule is why stacks show up in many parts of software, from small apps to large systems.
- Plate pile in a kitchen: last plate on, first plate off.
- Books in a small pile: new book on top, take top book to read.
- Cards on a discard pile in a game: place on top, draw from top.
Now let us talk about how a stack works in a little more detail. We will look at the actions you can do and what each one means. We will also see how the order of things is controlled by the LIFO rule. We will go slowly and show steps. We will use numbers to make it very clear. If you can follow the plate pile idea, then you can follow this part with no trouble. This part will make the rule feel real, and not just words. It will prepare you for the code later. It will also help you avoid mistakes like popping from an empty stack, which is a common error for new learners.
How a stack works (LIFO)
- Start with an empty stack: [].
- push(10): stack becomes [10] (10 is at top).
- push(20): stack becomes [10, 20] (20 is at top).
- push(30): stack becomes [10, 20, 30] (30 is at top).
- peek(): see 30, stack stays [10, 20, 30].
- pop(): remove 30, stack becomes [10, 20].
- pop(): remove 20, stack becomes [10].
- push(40): stack becomes [10, 40].
- pop(): remove 40, stack becomes [10].
- pop(): remove 10, stack becomes [].
The core actions of a stack are small, but they are very important. Each action does one clear thing. The push action adds a new item to the top. The pop action removes the top item and gives it back to you. The peek action looks at the top item but does not remove it. The isEmpty action tells you if the stack has zero items. The size action tells you how many items are there. When you work with these actions, you should always think about the top. That is the only face of the stack you touch. This focus makes code easy to test and easy to trust. But it also means you must be careful. If you try to pop when the stack is empty, that is a mistake called underflow. If you have a stack with a fixed size and you try to push when it is full, that is a mistake called overflow. Good code checks for these cases. Good code does not break if such a case happens. In the next part, we will list these actions and explain them simply.
Core operations
- push(x): add item x on top. If the stack is full (for fixed size), this can cause overflow. In a resizable stack, we grow the storage first.
- pop(): remove and return the top item. If the stack is empty, this is underflow. We must check first.
- peek(): return the top item but do not remove it. If empty, handle safely.
- isEmpty(): return true if there are zero items.
- size(): return how many items are in the stack right now.
- Check isEmpty() before you pop() or peek(). This prevents underflow.
- When you push, place the new item at the next top position, then move the top pointer.
- When you pop, move the top pointer back, then return the old top item.
- Keep size in sync whenever you push or pop.
- In a resizable array stack, when full, allocate a bigger array, copy items, then push.
It helps to know how fast a stack is. In many cases, the actions on the top are very fast. They take the same small time no matter how big the stack is. We call that constant time, or O(1). This is true for push, pop, and peek, because we always touch only the top slot. We do not search. We do not move many items. We just move a pointer or an index. But if you want to find an item by value somewhere deep inside the stack, that is slow, because you must look item by item. That is O(n), where n is how many items are in the stack. In practice, people use stacks for top work only, so they get the fast speed almost all the time. If you use a fixed size array for a stack, you might see a full stack case. In that case, you can pick a bigger array size or use a resizable type. The table below shows the common time cost for each action in simple terms.
Time complexity
| Operation | Average Time | Worst Time | Space |
|---|---|---|---|
| push | O(1) | O(1) | O(n) |
| pop | O(1) | O(1) | O(n) |
| peek | O(1) | O(1) | O(n) |
| isEmpty | O(1) | O(1) | O(n) |
| size | O(1) | O(1) | O(n) |
| search (by value) | O(n) | O(n) | O(n) |
- O(1) means time does not grow with more items. It stays small and steady.
- O(n) means time grows in a straight line with more items.
Now we will build a stack in Java using an array. This is a very common way. It is simple and fast. We will keep the code easy. We will store int values to make things clear. We will write the main actions: push, pop, peek, isEmpty, and size. We will also write a small resize method so the stack can grow when it gets full. This avoids overflow in normal use. After the code, we will explain each part in steps. We will show how the index moves. We will show which checks protect us from errors. If you copy this code into a Java file and run it, you can see the print lines and follow the flow. The goal here is not to be fancy. The goal is to make the idea stick in your head with a clear picture. Once you can read and run this, you can build other versions too, like with a linked list.
Stack in Java using array
public class ArrayStack {
private int[] data;
private int top; // points to next free position (size of stack)
public ArrayStack(int initialCapacity) {
if (initialCapacity <= 0) {
throw new IllegalArgumentException("Capacity must be > 0");
}
data = new int[initialCapacity];
top = 0;
}
public void push(int value) {
if (top == data.length) {
resize(data.length * 2);
}
data[top] = value;
top++;
}
public int pop() {
if (isEmpty()) {
throw new IllegalStateException("Underflow: stack is empty");
}
top--;
int value = data[top];
// Optional: clear slot
data[top] = 0;
return value;
}
public int peek() {
if (isEmpty()) {
throw new IllegalStateException("Stack is empty");
}
return data[top - 1];
}
public boolean isEmpty() {
return top == 0;
}
public int size() {
return top;
}
private void resize(int newCapacity) {
int[] newData = new int[newCapacity];
for (int i = 0; i < top; i++) {
newData[i] = data[i];
}
data = newData;
}
// Demo
public static void main(String[] args) {
ArrayStack stack = new ArrayStack(2);
stack.push(10);
stack.push(20);
stack.push(30); // triggers resize
System.out.println(stack.peek()); // 30
System.out.println(stack.pop()); // 30
System.out.println(stack.pop()); // 20
System.out.println(stack.size()); // 1
System.out.println(stack.pop()); // 10
System.out.println(stack.isEmpty()); // true
}
}
This step-by-step part explains the array stack code in a slow and friendly way. It tells you what each field and method does. It shows how the top index moves when you push and when you pop. It explains why we check if the stack is empty before we pop or peek. It also explains how resize works when the array is full, so you can keep pushing without error. If you are new to Java, do not worry. You can still follow because we talk about one small idea at a time. You can also run the main method to see real output. Reading code and output together will help the idea stick. Please take your time. Do not rush. Follow the numbered steps below and match them with the lines in the code. This will help you build a clear mental model. It will also help you find bugs faster in the future, because you will know exactly how the stack moves inside.
Step-by-step explanation
- Fields: We have data (the array that holds items) and top (how many items are in the stack, and the next free spot). When top is 0, the stack is empty. The top item is at index top – 1.
- Constructor: We check that capacity is positive. We make the array. We set top to 0, so the stack starts empty.
- push(value): We check if top == data.length. If true, the array is full, so we call resize to make it bigger. Then we write the value at data[top]. Then we move top up by 1.
- pop(): We check isEmpty(). If it is empty, we throw an error to avoid underflow. If not empty, we move top down by 1. Then we read the value at data[top] and return it. We also clear the slot to 0 (optional for neatness).
- peek(): We check empty first. Then we return data[top – 1] without changing top. The stack stays the same size.
- isEmpty() and size(): These are simple checks. They tell us if there are items and how many.
- resize(newCapacity): We make a new array. We copy current items from 0 to top – 1. Then we set data to the new array. Now the stack has more room.
- Demo in main: We build a small stack of size 2. We push 10 and 20. We push 30, which triggers resize. peek returns 30. Then we pop 30 and 20. size is now 1. Then we pop 10. Now isEmpty is true.
We will now build a stack in Java using a linked list. This is another common way. In this way, each item is a node that points to the next node. We only add and remove at the head of the list, which we treat as the top of the stack. This version grows as needed, so it does not need resize. It is good when you do not know the number of items in advance. It is also good when you want each push and pop to be very fast and steady. We will again use int values to keep it simple. After the code, we will give steps to explain how nodes are linked and unlinked. We will also compare this to the array version in plain words. You will see that the stack rule stays the same, even when the inner storage changes. This will help you learn that the idea is the main thing. The storage is just a choice.
Stack in Java using linked list
public class LinkedListStack {
private static class Node {
int value;
Node next;
Node(int v, Node n) { value = v; next = n; }
}
private Node top; // top points to the head node
private int size;
public LinkedListStack() {
top = null;
size = 0;
}
public void push(int value) {
Node newNode = new Node(value, top);
top = newNode;
size++;
}
public int pop() {
if (isEmpty()) {
throw new IllegalStateException("Underflow: stack is empty");
}
int v = top.value;
top = top.next;
size--;
return v;
}
public int peek() {
if (isEmpty()) {
throw new IllegalStateException("Stack is empty");
}
return top.value;
}
public boolean isEmpty() {
return top == null;
}
public int size() {
return size;
}
// Demo
public static void main(String[] args) {
LinkedListStack stack = new LinkedListStack();
stack.push(5);
stack.push(15);
stack.push(25);
System.out.println(stack.peek()); // 25
System.out.println(stack.pop()); // 25
System.out.println(stack.pop()); // 15
System.out.println(stack.size()); // 1
System.out.println(stack.pop()); // 5
System.out.println(stack.isEmpty()); // true
}
}
This step-by-step part explains how the linked list stack works. We will focus on the Node class, the top pointer, and the size field. We will see how push makes a new node and places it in front. We will see how pop removes that front node and moves the top pointer to the next node. We will also see how peek just reads from the top node. We will compare each action to the array version so you can see that the outward behavior is the same. The difference is only inside. This kind of thinking is powerful. It shows that a data structure is about rules and actions, not only about storage. Once you see that, many things feel simpler. You can swap storage types without fear as long as the rules stay the same. Now follow the steps and match them with the code to build a clear picture in your head.
Step-by-step explanation
- Node class: Each node holds an int value and a next pointer to the next node. If next is null, it is the last node.
- Fields: top points to the first node (the stack top). size counts how many items are in the stack.
- Constructor: We start with top = null and size = 0, so the stack is empty.
- push(value): We make a new node whose next is the current top. Then we set top to this new node. We add 1 to size. This is O(1).
- pop(): We check isEmpty() to avoid underflow. If not empty, we take the value of top, move top to top.next, and reduce size by 1. We return the value.
- peek(): We check empty. If safe, we return top.value without changing links. The stack stays the same size.
- isEmpty() and size(): Same idea as before, but now empty means top == null.
- Demo in main: We push 5, 15, 25. peek shows 25. We pop 25 and 15. size is 1. Then we pop 5. Now isEmpty is true.
In this part, we will talk about good sides, bad sides, and real uses of stacks. Knowing these will help you pick the stack when it is the right tool, and avoid it when it is not. We will keep the points simple and also give small details so you can see why each point matters. We will link each point to the LIFO rule, because that rule is the heart of a stack. If the job fits the rule, a stack will feel smooth and clean. If the job does not fit the rule, a stack may feel hard and messy. Read the points slowly and picture a plate pile as you go. This helps your brain make the idea solid.
Advantages, disadvantages, and applications
- Advantages
- Simple rule: Only use the top. This makes code small and easy to test.
- Fast top work: push, pop, and peek are O(1), so they are very quick even with many items.
- Safe order: LIFO keeps the newest item ready. This fits undo and back features well.
- Clear state: isEmpty and size make it easy to know the stack state at any time.
- Memory friendly: You only keep what you need, and you drop items by popping them.
- Disadvantages
- Limited access: You cannot get an item in the middle without popping the ones above it.
- Wrong fit for some tasks: If you need first-in-first-out, a queue is better, not a stack.
- Overflow/Underflow risk: If you do not check limits, you can crash or get errors.
- Search is slow: Looking for a value is O( n ), because you must scan items.
- Applications
- Undo/Redo: Text editors keep past actions on a stack so you can undo the last change first.
- Browser back: Pages you visit go on a stack. Back pops the last page.
- Call stack: When functions call other functions, the system uses a stack to remember where to return.
- Parsing: Check matching brackets (), {}, [], and parse math expressions with stacks.
- Backtracking: Try a path, and if it fails, pop and try another path (like in maze solving).
- DFS (Depth-First Search): Use a stack to explore deep paths first in graphs or trees.
There are some common mistakes that new learners make with stacks. It is normal to make them at first. The good news is that simple habits can stop these errors. In this part, we list the mistakes and give a clear fix for each one. We keep the language plain and the steps short. We also add test tips so you can catch problems early. If you follow these tips, your stack code will be more stable, and you will trust it more. You will also read and debug other people’s stack code better, because you will know what to look for. Use this part as a small checklist when you work with stacks in your projects.
Common mistakes and tips
- Popping an empty stack
- Problem: Calling pop or peek when isEmpty is true.
- Fix: Always check isEmpty() first, or handle the error with a clear message.
- Forgetting to move top/index
- Problem: After push or pop, not updating the index or pointer.
- Fix: In push, write value then add 1. In pop, subtract 1 then read the value.
- Not handling full array
- Problem: With a fixed array, pushing when full causes overflow.
- Fix: Use resize or check capacity before pushing.
- Mixing order rules
- Problem: Trying to get items from the middle. That breaks the stack idea.
- Fix: If you need middle or FIFO access, pick another structure like a queue or a list.
- Not testing step by step
- Tip steps:
- Start with empty stack tests.
- Push one item, test peek and pop.
- Push many items, then pop all to check order.
- Test underflow and expected errors.
- Test resize if using an array stack.
- Tip steps:
We are almost done. Let us close the topic with a short wrap up. This will help you lock the key ideas in your mind. We will keep this part simple and calm. We will repeat the most important words in bold so they stay fresh. After reading this, you should feel ready to try a small task on your own. You can write the array version or the linked list version, run tests, and print the steps to see the stack move. If you get stuck, come back to the steps and the lists above. They will guide you. Remember: the power of a stack is in its simple rule, not in complex code. Simple code is strong code. Keep it clean. Keep it small. Keep it clear.
Conclusion
- A stack follows LIFO: last in, first out. Work only happens at the top.
- Main actions are push, pop, peek, isEmpty, and size.
- Top actions are fast: usually O(1). Searching is O(n).
- Two common builds: array stack and linked list stack. Both follow the same rule.
- Use stacks for undo, back, call stack, parsing, and backtracking.
- Avoid underflow and overflow by checking and handling limits.
- Practice by writing code and tracing steps. This makes the idea strong in your mind.