๐Ÿ“š Stack in Java โ€“ A Complete Beginner’s Guide (Part 3)

๐Ÿ”— Stack Implementation Using Linked Lists (Push, Pop, Peek, isEmpty & Display)

Welcome to Part 3 of our Stack in Java series.

In Part 1, we learned:

  • โœ… What is a Stack?
  • โœ… LIFO Principle
  • โœ… Stack Terminologies
  • โœ… Applications of Stack

In Part 2, we learned:

  • โœ… Stack Implementation Using Arrays
  • โœ… Push Operation
  • โœ… Pop Operation
  • โœ… Peek Operation
  • โœ… isEmpty()
  • โœ… isFull()
  • โœ… Display Operation

Although an array implementation is simple and efficient, it has one major limitation:

The size of the stack is fixed.

If the array becomes full, no more elements can be inserted.

To overcome this limitation, we use a Linked List.

In this tutorial, you’ll learn how to implement a Stack using a Singly Linked List, where the stack can grow dynamically as memory is available.


๐Ÿ“š Table of Contents

  1. Why Use a Linked List?
  2. Stack Representation
  3. Node Structure
  4. Top Pointer
  5. Push Operation
  6. Pop Operation
  7. Peek Operation
  8. isEmpty()
  9. Display Operation
  10. Complete Java Program
  11. Dry Runs
  12. Time Complexity
  13. Advantages over Arrays
  14. Common Mistakes
  15. FAQs
  16. Conclusion

๐Ÿค” Why Implement Stack Using a Linked List?

Suppose an array-based stack has a capacity of 5.

10
20
30
40
50

Trying to push another element results in:

Stack Overflow

Even if your computer has plenty of free memory, the stack cannot grow because the array size is fixed.

A Linked List solves this problem.

Each new element is stored in a new node, so the stack grows dynamically.


๐Ÿ”— Stack Representation Using a Linked List

Unlike arrays, a linked list does not store elements in contiguous memory.

Each element is stored inside a Node.

Example

Top
 โ†“
+------+-----+
| 40 |  โ€ข----|----+
+------+-----+    |
                  |
          +------+-----+
          | 30 |  โ€ข----|----+
          +------+-----+    |
                             |
                     +------+-----+
                     | 20 |  โ€ข----|----+
                     +------+-----+    |
                                        |
                                +------+-----+
                                | 10 | NULL |
                                +------+-----+

Notice that the Top always points to the first node.


๐Ÿง  Why is the Top at the Beginning?

Suppose the stack is

Top

โ†“

40

โ†“

30

โ†“

20

โ†“

10

If the top is stored at the beginning,

both Push and Pop require changing only one reference.

Therefore,

both operations become

O(1)

๐Ÿ“ฆ Node Structure

Every node stores:

  • Data
  • Reference to the Next Node

Visual Representation

+------+------+
| Data | Next |
+------+------+

๐Ÿ’ป Java Node Class

class Node{

    int data;

    Node next;

    Node(int data){

        this.data = data;

        next = null;

    }

}

๐Ÿ“ Top Pointer

Instead of storing an index,

we store a reference.

Node top;

Initially

top = null

This means

the stack is empty.


โž• Push Operation

Push inserts a new node at the beginning.

Suppose

Current Stack

Top

โ†“

30

โ†“

20

โ†“

10

Push

40

Result

Top

โ†“

40

โ†“

30

โ†“

20

โ†“

10

๐Ÿ“ Algorithm

  1. Create a new node.
  2. Point it to the current Top.
  3. Move Top to the new node.

๐ŸŽจ Dry Run

Current

Top

โ†“

30

Create

40

Update

newNode.next = top

Update

top = newNode

Done.


๐Ÿ’ป Java Program โ€“ Push

public void push(int value){

    Node newNode = new Node(value);

    newNode.next = top;

    top = newNode;

}

โž– Pop Operation

Pop removes the top node.

Current

Top

โ†“

40

โ†“

30

โ†“

20

Pop

40

Result

Top

โ†“

30

โ†“

20

๐Ÿ“ Algorithm

  1. Check if the stack is empty.
  2. Store the top value.
  3. Move Top to the next node.
  4. Return the deleted value.

๐Ÿ’ป Java Program โ€“ Pop

public int pop(){

    if(top == null){

        System.out.println("Stack Underflow");

        return -1;

    }

    int value = top.data;

    top = top.next;

    return value;

}

๐Ÿ‘€ Peek Operation

Peek returns the top element

without removing it.

Current

Top

โ†“

40

โ†“

30

โ†“

20

Peek

40

Stack remains unchanged.


๐Ÿ’ป Java Program โ€“ Peek

public int peek(){

    if(top == null){

        System.out.println("Stack is Empty");

        return -1;

    }

    return top.data;

}

โ“ isEmpty()

Checks whether the stack contains any elements.


๐Ÿ’ป Java Program

public boolean isEmpty(){

    return top == null;

}

๐Ÿ“‹ Display Operation

Display starts from Top.

Current

Top

โ†“

40

โ†“

30

โ†“

20

โ†“

10

Output

40

30

20

10

๐Ÿ’ป Java Program โ€“ Display

public void display(){

    if(top == null){

        System.out.println("Stack is Empty");

        return;

    }

    Node temp = top;

    while(temp != null){

        System.out.println(temp.data);

        temp = temp.next;

    }

}

๐Ÿ’ป Complete Java Program

class Node{

    int data;

    Node next;

    Node(int data){

        this.data = data;

        next = null;

    }

}

public class Stack{

    Node top;

    public void push(int value){

        Node newNode = new Node(value);

        newNode.next = top;

        top = newNode;

    }

    public int pop(){

        if(top == null){

            System.out.println("Stack Underflow");

            return -1;

        }

        int value = top.data;

        top = top.next;

        return value;

    }

    public int peek(){

        if(top == null){

            System.out.println("Stack is Empty");

            return -1;

        }

        return top.data;

    }

    public boolean isEmpty(){

        return top == null;

    }

    public void display(){

        if(top == null){

            System.out.println("Stack is Empty");

            return;

        }

        Node temp = top;

        System.out.println("\nStack Elements:");

        while(temp != null){

            System.out.println(temp.data);

            temp = temp.next;

        }

    }

    public static void main(String args[]){

        Stack s = new Stack();

        s.push(10);

        s.push(20);

        s.push(30);

        s.push(40);

        s.display();

        System.out.println("\nTop Element = " + s.peek());

        System.out.println("\nDeleted = " + s.pop());

        s.display();

        System.out.println("\nIs Empty? " + s.isEmpty());

    }

}

Output

Stack Elements:

40
30
20
10

Top Element = 40

Deleted = 40

Stack Elements:

30
20
10

Is Empty? false

๐Ÿ“Š Time Complexity

OperationTime Complexity
PushO(1)
PopO(1)
PeekO(1)
isEmptyO(1)
DisplayO(n)

๐Ÿ’พ Space Complexity

Suppose the stack contains n nodes.

Memory required

O(n)

Unlike arrays,

memory is allocated only when a new node is created.


โš–๏ธ Array vs Linked List Implementation

FeatureArray StackLinked List Stack
Memory SizeFixedDynamic
OverflowPossibleOnly when memory is exhausted
PushO(1)O(1)
PopO(1)O(1)
Memory UsageMay waste unused spaceAllocates memory only when needed
ImplementationSimpleSlightly more complex

๐ŸŒŸ Advantages of Linked List Stack

โœ… Dynamic size

โœ… No fixed capacity

โœ… No wasted array space

โœ… Efficient Push and Pop operations

โœ… Better memory utilization


โŒ Disadvantages

โŒ Extra memory is required for storing the next reference.

โŒ Nodes are not stored contiguously, so cache performance may be lower than arrays.

โŒ Slightly more complex implementation than an array-based stack.


โš ๏ธ Common Mistakes

โŒ Forgetting to update top

Wrong

newNode.next = top;

Correct

top = newNode;

โŒ Forgetting the Underflow Check

Never access

top.data

without first checking

top == null

โŒ Using the Last Node as Top

For a linked-list implementation, the Top should always be the first node, not the last. Otherwise, Push and Pop operations would require traversal and become O(n) instead of O(1).


โ“ Frequently Asked Questions

Q1. Why is the Top stored at the beginning?

So that Push and Pop can be performed in O(1) time.


Q2. Can a Linked List Stack overflow?

It can only overflow when the system runs out of available memory.


Q3. Which implementation is better?

  • Array: Better when the maximum size is known and memory locality is important.
  • Linked List: Better when the stack size is unpredictable.

Q4. Is Push faster in a Linked List?

No. Push is O(1) in both array and linked-list implementations.


Q5. Why doesn’t a Linked List Stack require isFull()?

Because it grows dynamically and does not have a predefined size limit.


๐ŸŽฏ Key Takeaways

  • ๐Ÿ”— A Linked List provides a dynamic implementation of a Stack.
  • ๐Ÿ“ The Top points to the first node.
  • โž• Push inserts a node at the beginning.
  • โž– Pop removes the first node.
  • ๐Ÿ‘€ Peek returns the first node’s data.
  • ๐Ÿš€ Push, Pop, and Peek all take O(1) time.
  • ๐Ÿ’พ Memory is allocated dynamically, avoiding the fixed-size limitation of arrays.

๐ŸŽ‰ Conclusion

Implementing a Stack using a Linked List eliminates the biggest drawback of an array-based stackโ€”its fixed capacity. Since nodes are created dynamically, the stack can grow as needed, making it ideal for applications where the number of elements is not known in advance.

Although each node requires extra memory for storing the next reference, the flexibility and scalability often outweigh this overhead.

๐Ÿ‘‰ In Part 4, we’ll explore the real-world applications of Stack, including:

  • ๐Ÿ” Function Call Stack
  • ๐Ÿ”„ Recursion
  • ๐Ÿงฎ Expression Evaluation
  • ๐Ÿ“ Parentheses Matching
  • ๐Ÿ”ค Infix to Postfix Conversion
  • ๐Ÿ”ก Infix to Prefix Conversion
  • ๐ŸŒ Browser History
  • โœ๏ธ Undo & Redo
  • ๐ŸŒณ Depth First Search (DFS)
  • ๐Ÿ’ป Java Virtual Machine (JVM) Stack
  • ๐ŸŽฏ Complete Java examples for important applications

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *