DSA in Kotlin

Teaching Data Structures and Algorithms (DSA) in Kotlin involves covering fundamental concepts like arrays, linked lists, stacks, queues, trees, graphs, sorting, and searching, while implementing them in Kotlin. Since this is a broad topic, I’ll provide a structured roadmap, explain key concepts, and share Kotlin code examples for some essential data structures and algorithms. I’ll keep it concise yet comprehensive, focusing on practical implementations. If you want to dive deeper into any specific topic, let me know!
Roadmap for Learning DSA in Kotlin
Basics of Kotlin: Ensure familiarity with Kotlin syntax, classes, functions, collections, and lambdas.
Core Data Structures:
Arrays and Lists
Linked Lists
Stacks and Queues
Hash Tables
Trees (Binary Trees, Binary Search Trees)
Graphs
Heaps
Core Algorithms:
Searching: Linear Search, Binary Search
Sorting: Bubble Sort, Merge Sort, Quick Sort
Recursion and Backtracking
Dynamic Programming
Graph Algorithms: BFS, DFS, Dijkstra’s
Practice: Solve problems on platforms like LeetCode, HackerRank, or Codeforces using Kotlin.
Step 1: Kotlin Basics for DSA
Kotlin is a modern, concise language that works well for DSA due to its expressive syntax and built-in collections. Key features for DSA:
Collections: List, MutableList, Map, Set.
Null Safety: Use ? for nullable types, !! for non-null assertions.
Data Classes: Simplify creating classes for nodes or data holders.
Lambdas and Higher-Order Functions: Useful for functional programming in algorithms.
Example: Creating a simple data class for a linked list node.
kotlin
data class Node<T>(var value: T, var next: Node<T>? = null)
Step 2: Core Data Structures in Kotlin
1. Arrays and Lists
Kotlin provides Array and MutableList for dynamic arrays. Use arrayOf for fixed-size arrays and mutableListOf for resizable lists.
Example: Reversing an Array
kotlin
fun reverseArray(arr: IntArray): IntArray {
var start = 0
var end = arr.size - 1
while (start < end) {
arr[start] = arr[end].also { arr[end] = arr[start] } // Swap
start++
end--
}
return arr
}
fun main() {
val arr = intArrayOf(1, 2, 3, 4, 5)
println(reverseArray(arr).contentToString()) // [5, 4, 3, 2, 1]
}
2. Linked List
A linked list consists of nodes, each containing a value and a reference to the next node.
Example: Singly Linked List with Insert and Print
kotlin
class LinkedList<T> {
private var head: Node<T>? = null
fun insert(value: T) {
val newNode = Node(value)
if (head == null) {
head = newNode
} else {
var current = head
while (current?.next != null) {
current = current.next
}
current?.next = newNode
}
}
fun printList() {
var current = head
while (current != null) {
print("${current.value} -> ")
current = current.next
}
println("null")
}
}
fun main() {
val list = LinkedList<Int>()
list.insert(1)
list.insert(2)
list.insert(3)
list.printList() // 1 -> 2 -> 3 -> null
}
3. Stack
A stack follows Last-In-First-Out (LIFO). Use Kotlin’s ArrayDeque or implement your own.
Example: Stack Implementation
kotlin
class Stack<T> {
private val items = mutableListOf<T>()
fun push(item: T) = items.add(item)
fun pop(): T? = if (items.isNotEmpty()) items.removeAt(items.size - 1) else null
fun peek(): T? = items.lastOrNull()
fun isEmpty(): Boolean = items.isEmpty()
}
fun main() {
val stack = Stack<Int>()
stack.push(1)
stack.push(2)
println(stack.pop()) // 2
println(stack.peek()) // 1
}
4. Queue
A queue follows First-In-First-Out (FIFO). Use ArrayDeque or implement a custom queue.
Example: Queue Implementation
kotlin
class Queue<T> {
private val items = ArrayDeque<T>()
fun enqueue(item: T) = items.addLast(item)
fun dequeue(): T? = items.removeFirstOrNull()
fun peek(): T? = items.firstOrNull()
fun isEmpty(): Boolean = items.isEmpty()
}
fun main() {
val queue = Queue<Int>()
queue.enqueue(1)
queue.enqueue(2)
println(queue.dequeue()) // 1
println(queue.peek()) // 2
}
5. Binary Search Tree (BST)
A BST is a tree where each node has at most two children, and the left subtree contains smaller values, the right subtree larger values.
Example: BST with Insert and In-Order Traversal
kotlin
data class TreeNode(val value: Int, var left: TreeNode? = null, var right: TreeNode? = null)
class BST {
var root: TreeNode? = null
fun insert(value: Int) {
root = insertRec(root, value)
}
private fun insertRec(node: TreeNode?, value: Int): TreeNode {
if (node == null) return TreeNode(value)
if (value < node.value) {
node.left = insertRec(node.left, value)
} else if (value > node.value) {
node.right = insertRec(node.right, value)
}
return node
}
fun inOrder() {
inOrderRec(root)
println()
}
private fun inOrderRec(node: TreeNode?) {
if (node != null) {
inOrderRec(node.left)
print("${node.value} ")
inOrderRec(node.right)
}
}
}
fun main() {
val bst = BST()
bst.insert(5)
bst.insert(3)
bst.insert(7)
bst.inOrder() // 3 5 7
}
Step 3: Core Algorithms in Kotlin
1. Linear Search
Find an element in an array by checking each element.
kotlin
fun linearSearch(arr: IntArray, target: Int): Int {
for (i in arr.indices) {
if (arr[i] == target) return i
}
return -1
}
fun main() {
val arr = intArrayOf(4, 2, 7, 1, 9)
println(linearSearch(arr, 7)) // 2
}
2. Binary Search
Search a sorted array by dividing the search interval in half.
kotlin
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
arr[mid] < target -> left = mid + 1
else -> right = mid - 1
}
}
return -1
}
fun main() {
val arr = intArrayOf(1, 3, 5, 7, 9)
println(binarySearch(arr, 5)) // 2
}
3. Merge Sort
A divide-and-conquer sorting algorithm that splits the array, sorts, and merges.
kotlin
fun mergeSort(arr: IntArray, left: Int, right: Int) {
if (left < right) {
val mid = left + (right - left) / 2
mergeSort(arr, left, mid)
mergeSort(arr, mid + 1, right)
merge(arr, left, mid, right)
}
}
fun merge(arr: IntArray, left: Int, mid: Int, right: Int) {
val leftArray = arr.copyOfRange(left, mid + 1)
val rightArray = arr.copyOfRange(mid + 1, right + 1)
var i = 0
var j = 0
var k = left
while (i < leftArray.size && j < rightArray.size) {
if (leftArray[i] <= rightArray[j]) {
arr[k++] = leftArray[i++]
} else {
arr[k++] = rightArray[j++]
}
}
while (i < leftArray.size) arr[k++] = leftArray[i++]
while (j < rightArray.size) arr[k++] = rightArray[j++]
}
fun main() {
val arr = intArrayOf(5, 2, 8, 1, 9)
mergeSort(arr, 0, arr.size - 1)
println(arr.contentToString()) // [1, 2, 5, 8, 9]
}
Step 4: Practice and Resources
Practice Platforms:
LeetCode (Kotlin supported)
HackerRank
Codeforces (use Kotlin for competitive programming)
Books:
"Introduction to Algorithms" by Cormen (CLRS)
"Data Structures and Algorithms in Kotlin" (online tutorials or blogs)
Online Courses:
Coursera: Algorithms by Princeton
Udemy: DSA in Kotlin or Java (similar syntax)
Tips for Learning DSA in Kotlin
Start Small: Master arrays and linked lists before tackling trees or graphs.
Write Code: Implement each data structure and algorithm yourself.
Understand Time Complexity: Learn Big-O notation (e.g., O(n), O(log n), O(n²)).
Debugging: Use Kotlin’s println or IDE debuggers to trace your code.
Leverage Kotlin Features: Use collections, lambdas, and extension functions to write cleaner code.
What’s Next?
Want to focus on a specific data structure (e.g., graphs) or algorithm (e.g., dynamic programming)?
Need more advanced examples or problem-solving techniques?
Interested in competitive programming with Kotlin?
Let me know how you’d like to proceed!
Subscribe to my newsletter
Read articles from Singaraju Saiteja directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Singaraju Saiteja
Singaraju Saiteja
I am an aspiring mobile developer, with current skill being in flutter.