Skip to main content
Kotlin Basics
CHAPTER 29 Beginner

Data Structures and Algorithms in Kotlin

Updated: May 18, 2026
5 min read

# CHAPTER 29

Data Structures and Algorithms in Kotlin

1. Chapter Introduction

Understanding syntax makes you a programmer; understanding Data Structures and Algorithms (DSA) makes you a Software Engineer. When building systems that scale to millions of users, choosing the right data structure dictates whether your app responds in 1 millisecond or freezes for 10 seconds. While Kotlin's standard library provides many of these, understanding how they work under the hood is critical for technical interviews.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Implement a custom Stack and Queue.
  • Understand the mechanics of a Singly Linked List.
  • Implement Binary Search for O(log N) lookups.
  • Implement basic Sorting Algorithms (Bubble Sort).

3. The Stack (LIFO)

A Stack follows the Last In, First Out (LIFO) principle. Think of a stack of plates: the last plate you put on top is the first one you take off. This is used in Android for "Back Navigation" (pressing the back button pops the current screen off the stack).
kotlin
1234567891011121314151617181920212223
class Stack<T> {
    private val elements = mutableListOf<T>()

    // Add to the top
    fun push(item: T) = elements.add(item)

    // Remove from the top
    fun pop(): T? {
        if (elements.isEmpty()) return null
        return elements.removeAt(elements.size - 1)
    }

    // Look at the top without removing
    fun peek(): T? = elements.lastOrNull()
}

fun main() {
    val stack = Stack<String>()
    stack.push("Home Screen")
    stack.push("Profile Screen")
    
    println(stack.pop()) // Output: Profile Screen
}

4. The Queue (FIFO)

A Queue follows the First In, First Out (FIFO) principle. Think of a line at a grocery store. The first person in line is served first. This is used for background task scheduling.
kotlin
1234567891011121314151617181920
class Queue<T> {
    private val elements = mutableListOf<T>()

    // Add to the back of the line
    fun enqueue(item: T) = elements.add(item)

    // Remove from the front of the line
    fun dequeue(): T? {
        if (elements.isEmpty()) return null
        return elements.removeAt(0)
    }
}

fun main() {
    val printQueue = Queue<String>()
    printQueue.enqueue("Document1.pdf")
    printQueue.enqueue("Image.png")
    
    println(printQueue.dequeue()) // Output: Document1.pdf
}

5. Linked Lists

A standard Array stores items in sequential memory blocks. A Linked List scatters items across memory, but each item (Node) holds a pointer to the *next* item. It is slower to search, but much faster at inserting data in the middle.
kotlin
12345678910111213141516171819202122232425262728293031323334353637
// The Node holds the data, and a reference to the next Node!
class Node<T>(val value: T, var next: Node<T>? = null)

class LinkedList<T> {
    var head: Node<T>? = null

    fun append(value: T) {
        if (head == null) {
            head = Node(value)
            return
        }
        
        // Traverse to the end of the list
        var current = head
        while (current?.next != null) {
            current = current.next
        }
        current?.next = Node(value)
    }

    fun printList() {
        var current = head
        while (current != null) {
            print("${current.value} -> ")
            current = current.next
        }
        println("null")
    }
}

fun main() {
    val list = LinkedList<Int>()
    list.append(10)
    list.append(20)
    list.append(30)
    list.printList() // Output: 10 -> 20 -> 30 -> null
}
If you have a sorted list of 1,000,000 names, searching from the beginning (Linear Search) could take 1,000,000 checks. Binary Search cuts the list in half every time, finding the answer in a maximum of 20 checks! Time complexity: O(log N).
kotlin
12345678910111213141516171819202122
fun binarySearch(arr: IntArray, target: Int): Int {
    var left = 0
    var right = arr.size - 1

    while (left <= right) {
        val mid = left + (right - left) / 2

        when {
            arr[mid] == target -> return mid      // Found it!
            arr[mid] < target -> left = mid + 1   // Target is in the right half
            else -> right = mid - 1               // Target is in the left half
        }
    }
    return -1 // Not found
}

fun main() {
    // Array MUST be sorted for Binary Search to work!
    val sortedNumbers = intArrayOf(2, 5, 8, 12, 16, 23, 38, 56, 72, 91)
    val index = binarySearch(sortedNumbers, 23)
    println("Found at index: $index") // Output: 5
}

7. Sorting: Bubble Sort

While Kotlin provides .sorted(), knowing how sorting works is crucial. Bubble sort compares adjacent elements and swaps them if they are in the wrong order. It is slow (O(N^2)), but easy to understand.
kotlin
12345678910111213141516171819
fun bubbleSort(arr: IntArray) {
    val n = arr.size
    for (i in 0 until n - 1) {
        for (j in 0 until n - i - 1) {
            if (arr[j] > arr[j + 1]) {
                // Swap the elements
                val temp = arr[j]
                arr[j] = arr[j + 1]
                arr[j + 1] = temp
            }
        }
    }
}

fun main() {
    val numbers = intArrayOf(64, 34, 25, 12, 22, 11, 90)
    bubbleSort(numbers)
    println(numbers.joinToString(", ")) // 11, 12, 22, 25, 34, 64, 90
}

8. Common Mistakes

  • Using Binary Search on an unsorted list: Binary search mathematically relies on the data being sorted (Left is smaller, Right is larger). If the list is unsorted, it will fail silently and return -1.

9. Best Practices

  • Use the Standard Library in Production: While implementing a Stack manually is great for interviews, in real Kotlin applications, you should use ArrayDeque (Double-ended queue), which serves as an incredibly fast Stack and Queue natively.

10. Exercises

*(Theoretical)*
  1. 1. What data structure would you use to build an "Undo" feature in a text editor? (Answer: Stack).
  1. 2. What data structure would you use to manage printer jobs sent from 10 different computers? (Answer: Queue).

11. MCQs with Answers

Question 1

Which data structure follows the Last In, First Out (LIFO) principle?

Question 2

Which data structure follows the First In, First Out (FIFO) principle?

Question 3

In a Singly Linked List, what does each "Node" hold?

Question 4

What is a major advantage of a Linked List over an Array?

Question 5

What is the Time Complexity of Binary Search?

Question 6

What is a strict requirement for an Array before you can use Binary Search on it?

Question 7

What sorting algorithm repeatedly steps through a list, compares adjacent elements, and swaps them if they are in the wrong order?

Question 8

In Kotlin, what standard library collection is recommended to be used as both a Stack and a Queue in production?

Question 9

Which Stack method adds an item to the top?

Question 10

Which Stack method removes and returns the item on top?

12. Interview Questions

  • Q: Explain how Binary Search works and why it is drastically faster than Linear Search.
  • Q: Compare an Array with a Linked List. When would you use one over the other?

13. Summary

Mastering Data Structures and Algorithms transforms how you view problem-solving. Knowing that Stacks power "Undo" buttons, Queues power task schedulers, and Binary Search powers rapid database indexing allows you to choose the correct architectural tools. While Kotlin provides excellent built-in abstractions, knowing the underlying mechanics is essential for writing hyper-efficient software.

14. Next Chapter Recommendation

We have reached the end of our journey! In Chapter 30: Final Projects and Real-World Applications, we will review architectural blueprints for 6 real-world applications you can build to solidify your Kotlin expertise.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·