Skip to content
Data Structures Explained — Arrays, Linked Lists, Stacks & Queues

Data Structures Explained — Arrays, Linked Lists, Stacks & Queues

DodaTech Updated Jun 6, 2026 9 min read

Data structures are ways of organizing and storing data so it can be used efficiently — the foundation of every software application you use.

What You’ll Learn

In this tutorial, you’ll learn about arrays, linked lists, stacks, and queues — how they work, when to use each, and how to implement them in Python.

Why It Matters

Every program uses data structures. The “Undo” feature in your text editor uses a stack. Print jobs are managed with a queue. Your music playlist is a linked list. Choosing the right data structure can make or break your application’s performance.

Real-World Use

When you press Ctrl+Z in a text editor, the application pops the last action from a stack. When you send a document to the printer, it waits in a queue. Your phone’s contact list is an array. Understanding these structures helps you write better software.

    flowchart TD
  A[Data Structures] --> B[Linear]
  A --> C[Non-Linear]
  B --> D[Arrays]
  B --> E[Linked Lists]
  B --> F[Stacks]
  B --> G[Queues]
  C --> H[Trees]
  C --> I[Graphs]
  

Arrays

An array is the simplest data structure — a contiguous block of memory where each element is stored next to its neighbor.

Think of an array like a row of lockers at a gym. Each locker has a number (index), and you can open any locker directly if you know its number. You don’t need to search through all the lockers — just go to number 7.

# Arrays in Python (using lists)
fruits = ["Apple", "Banana", "Cherry", "Date", "Elderberry"]

# Access by index - O(1) - instant!
print(f"Third fruit: {fruits[2]}")  # Index 2 = Cherry

# Append to end - O(1) amortized
fruits.append("Fig")
print(f"After append: {fruits}")

# Insert at beginning - O(n) - requires shifting elements
fruits.insert(0, "Apricot")
print(f"After insert at 0: {fruits}")

# Remove from middle - O(n) - requires shifting elements
fruits.remove("Date")
print(f"After removal: {fruits}")

Expected output:

Third fruit: Cherry
After append: ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig']
After insert at 0: ['Apricot', 'Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig']
After removal: ['Apricot', 'Apple', 'Banana', 'Cherry', 'Elderberry', 'Fig']

Array operations and their Big O:

OperationTimeWhy
Access by indexO(1)Direct memory address calculation
Append to endO(1)Add at the end (amortized)
Insert at beginningO(n)Every element must shift right
Remove from middleO(n)Every element must shift left
SearchO(n)Must check each element until found

When to use arrays: When you need fast access by index and mostly add/remove at the end. Good for contact lists, high scores, and any fixed-size collection.

Linked Lists

A linked list stores elements as nodes, where each node contains data and a pointer to the next node. Unlike arrays, elements aren’t stored in contiguous memory.

Think of a linked list like a treasure hunt. Each clue tells you where to find the next clue. To find the last clue, you must follow the chain from the beginning.

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class LinkedList:
    def __init__(self):
        self.head = None

    def append(self, data):
        """Add to the end - O(n)"""
        new_node = Node(data)
        if not self.head:
            self.head = new_node
            return
        current = self.head
        while current.next:
            current = current.next
        current.next = new_node

    def prepend(self, data):
        """Add to the beginning - O(1)"""
        new_node = Node(data)
        new_node.next = self.head
        self.head = new_node

    def display(self):
        """Print all elements"""
        current = self.head
        elements = []
        while current:
            elements.append(str(current.data))
            current = current.next
        print(" -> ".join(elements))

# Usage
playlist = LinkedList()
playlist.append("Song A")
playlist.append("Song B")
playlist.prepend("Favorite Song")
playlist.append("Song C")

print("Music Playlist:")
playlist.display()

Expected output:

Music Playlist:
Favorite Song -> Song A -> Song B -> Song C

Linked list operations:

OperationTimeWhy
Insert at beginningO(1)Just update head pointer
Insert at endO(n)Must traverse to last node
Access by indexO(n)Must traverse from head
SearchO(n)Must traverse the list

When to use linked lists: When you need fast insertions/deletions at the beginning or middle. Music playlists, image viewers (prev/next), and blockchain blocks use linked lists.

Array vs Linked List

AspectArrayLinked List
MemoryContiguous (one block)Scattered (nodes linked by pointers)
AccessO(1) by indexO(n) traverse
Insert startO(n) shiftO(1) update head
Insert endO(1) amortizedO(n) traverse
Memory overheadLowHigher (stores pointers)

Stacks

A stack follows Last In, First Out (LIFO) — like a stack of plates. You add plates to the top and take plates from the top. The last plate you put on is the first one you take off.

class Stack:
    def __init__(self):
        self.items = []

    def push(self, item):
        """Add to top - O(1)"""
        self.items.append(item)

    def pop(self):
        """Remove from top - O(1)"""
        if self.is_empty():
            return None
        return self.items.pop()

    def peek(self):
        """View top without removing - O(1)"""
        if self.is_empty():
            return None
        return self.items[-1]

    def is_empty(self):
        return len(self.items) == 0

# Simulate the Undo feature
editor = Stack()

print("Typing some text...")
editor.push("Hello")
editor.push("Hello World")
editor.push("Hello World!")
print(f"Current text: '{editor.peek()}'")

print("\nUndo last action...")
editor.pop()
print(f"After undo: '{editor.peek()}'")

print("Undo again...")
editor.pop()
print(f"After undo: '{editor.peek()}'")

Expected output:

Typing some text...
Current text: 'Hello World!'

Undo last action...
After undo: 'Hello World'

Undo again...
After undo: 'Hello'

Stack operations: All operations are O(1).

Real-world uses of stacks:

  • Undo/Redo in text editors
  • Browser history (back button)
  • Function call stack — Python uses a stack to track function calls
  • Expression evaluation — compilers use stacks to evaluate arithmetic

Queues

A queue follows First In, First Out (FIFO) — like a line at a coffee shop. The first person in line is the first person served.

from collections import deque

class Queue:
    def __init__(self):
        self.items = deque()

    def enqueue(self, item):
        """Add to back - O(1)"""
        self.items.append(item)

    def dequeue(self):
        """Remove from front - O(1)"""
        if self.is_empty():
            return None
        return self.items.popleft()

    def peek(self):
        """View front without removing - O(1)"""
        if self.is_empty():
            return None
        return self.items[0]

    def is_empty(self):
        return len(self.items) == 0

    def size(self):
        return len(self.items)

# Simulate a print queue
printer = Queue()

print("Sending print jobs...")
printer.enqueue("Report.pdf")
printer.enqueue("Invoice.pdf")
printer.enqueue("Photo.jpg")
print(f"Queue size: {printer.size()}")

print("\nProcessing print jobs:")
while not printer.is_empty():
    job = printer.dequeue()
    print(f"Printing: {job}")

Expected output:

Sending print jobs...
Queue size: 3

Processing print jobs:
Printing: Report.pdf
Printing: Invoice.pdf
Printing: Photo.jpg

Queue operations: All operations are O(1) when using collections.deque.

Real-world uses of queues:

  • Print queues — documents wait their turn
  • Task scheduling — CPU schedules processes
  • Message queues — RabbitMQ, Kafka
  • Breadth-first search — graph traversal algorithm

Security Applications

Stack-based buffer overflow — One of the most famous security vulnerabilities. When a program writes more data to a stack buffer than it can hold, the overflow can overwrite the return address, allowing attackers to execute arbitrary code.

Queue-based rate limitingAPIs use queues to enforce rate limits. Each request enters a queue, and requests over the limit are dropped to prevent abuse.

Array bounds checking — Accessing array indices outside bounds (like arr[100] for a 10-element array) is a common vulnerability. Python catches this, but C and C++ don’t — leading to buffer overflow bugs.

Common Mistakes Beginners Make

1. Confusing stack and queue

Stack = LIFO (last in, first out). Queue = FIFO (first in, first out). Remember: stack of plates, queue of people.

2. Using an array when a linked list is better

If you need frequent insertions at the beginning, use a linked list. Arrays require O(n) shifting for this.

3. Forgetting that Python lists are dynamic

Python lists handle resizing automatically. You don’t need to specify size upfront like in C or Java.

4. Not using deque for queues

list.pop(0) is O(n). Use collections.deque for O(1) queue operations.

5. Infinite loops in linked lists

If a linked list has a cycle (a node pointing back to a previous node), traversal never ends. Always test with small examples.

Practice Questions

  1. What’s the difference between an array and a linked list? Arrays store elements in contiguous memory, offering O(1) index access but O(n) insertions at the start. Linked lists store nodes with pointers, offering O(1) insertion at the start but O(n) index access.

  2. What does LIFO stand for? Last In, First Out. The last element added to a stack is the first one removed.

  3. Give three real-world uses of a queue. Print queues, CPU task scheduling, and message queue systems.

  4. Why does inserting at the beginning of an array take O(n) time? All existing elements must shift one position to the right to make room.

  5. What data structure would you use for a browser’s back button? A stack. Each visited page is pushed onto the stack. The back button pops the top page.

Challenge

Implement a deque (double-ended queue) that supports O(1) insertion and removal at both ends. Use it to check if a word is a palindrome (“racecar” reads the same forward and backward).

Real-World Task

Open your browser and visit 5 websites. Press the back button 3 times. Can you trace the stack operations? Which sites were pushed and popped?

FAQ

Do I need to implement data structures from scratch?
Not in most languages. Python has lists (dynamic arrays), collections.deque (queues), and you can use list as a stack. But understanding how they work helps you choose the right one.
What’s the difference between a stack and a queue?
Stack: LIFO (Last In, First Out). Queue: FIFO (First In, First Out). Think stack = pile of plates, queue = line of people.
What’s a doubly linked list?
A linked list where each node points to both the next AND previous node. This allows O(1) deletion from both ends.
What data structure does Python use for lists?
Dynamic arrays. When the array fills up, Python allocates a larger block (usually 1.125x the current size) and copies elements over.
Which data structure is fastest?
It depends on the operation. Arrays are fastest for indexed access. Linked lists are fastest for front insertions. Choose based on your usage pattern.

Try It Yourself

▶ Try It Yourself Edit the code and click Run

Mini Project: Task Scheduler

Build a simple task scheduler using a queue:

  1. Users can add tasks with priorities
  2. A worker processes tasks in FIFO order
  3. Track completed and pending tasks

Security angle: Message queues are used in security systems to process threat alerts. Each alert enters a queue and is analyzed by workers in order, ensuring no threat is missed.

What’s Next

Before moving on, you should understand:

  • Array vs linked list trade-offs
  • Stack (LIFO) vs Queue (FIFO) behavior
  • Real-world applications of each data structure

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

What’s Next

Congratulations on completing this Data Structures tutorial! Here’s where to go from here:

  • Practice daily — Consistency is more important than long study sessions
  • Build a project — Apply what you learned by building something real
  • Explore related topics — Check out other tutorials in the same category
  • Join the community — Discuss with other learners and share your progress

Remember: every expert was once a beginner. Keep coding!

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro