) {
76 | for (i in arr.indices) {
77 | var min = arr.findMinimumIndex(i)
78 | for (j in i + 1 until arr.size) {
79 | if (arr[j] < arr[min]) {
80 | min = j
81 | }
82 | }
83 | // Move minimum element at current i.
84 | val key = arr[min]
85 | while (min > i) {
86 | arr[min] = arr[min - 1]
87 | min--
88 | }
89 | arr[i] = key
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/config/main.md:
--------------------------------------------------------------------------------
1 | # Data structures and algorithms in pure Kotlin
2 |
3 | A repository that organizes various data structures, algorithms, and solutions to problems in Kotlin in a structured format
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | ## Overview
23 |
24 | The repository is a collection of open-source implementations of a variety of algorithms implemented in Kotlin and
25 | licensed under MIT License.
26 | The implementations and their associated documentations are meant to provide a learning resource for educators and
27 | students.
28 | Hence, one may find more than one implementation for the same objective but using different algorithm strategies and
29 | optimizations.
30 |
31 | ## Features
32 |
33 | * The repository provides implementations of various algorithms in one of the most fundamental general purpose languages
34 | - [Kotlin](https://kotlinlang.org/)).
35 | * Well documented source code with detailed explanations provide a valuable resource for educators and students alike.
36 | * Source codes are compiled and tested
37 | * Self-checks within programs ensure correct implementations with confidence.
38 | * Modular implementations and OpenSource licensing enable the functions to be utilized conveniently in other
39 | applications.
40 | * Makefile
41 | * JUnit 5
42 | * Code checks (detekt, ktlint, spotless)
43 | * CI
44 |
--------------------------------------------------------------------------------
/src/test/kotlin/dev/shtanko/algorithms/leetcode/TwoSumTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 |
4 | * Copyright (c) 2022 Oleksii Shtanko
5 |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 |
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package dev.shtanko.algorithms.leetcode
26 |
27 | import dev.shtanko.algorithms.utils.measureTime
28 | import org.assertj.core.api.Assertions.assertThat
29 | import org.junit.jupiter.api.extension.ExtensionContext
30 | import org.junit.jupiter.params.ParameterizedTest
31 | import org.junit.jupiter.params.provider.Arguments
32 | import org.junit.jupiter.params.provider.ArgumentsProvider
33 | import org.junit.jupiter.params.provider.ArgumentsSource
34 | import org.junit.jupiter.params.support.ParameterDeclarations
35 | import java.util.stream.Stream
36 |
37 | abstract class TwoSumTest(private val strategy: T) {
38 | @ParameterizedTest
39 | @ArgumentsSource(InputArgumentsProvider::class)
40 | fun `two sum test`(
41 | array: IntArray,
42 | target: Int,
43 | expected: IntArray,
44 | ) {
45 | measureTime("Two sum array ${array.toList()}") {
46 | val actual = strategy(array, target)
47 | assertThat(actual).isEqualTo(expected)
48 | }
49 | }
50 |
51 | private class InputArgumentsProvider : ArgumentsProvider {
52 | override fun provideArguments(
53 | parameters: ParameterDeclarations,
54 | context: ExtensionContext,
55 | ): Stream = Stream.of(
56 | Arguments.of(
57 | intArrayOf(),
58 | 0,
59 | intArrayOf(),
60 | ),
61 | Arguments.of(
62 | intArrayOf(4, 8, 15, 16, 23),
63 | 9,
64 | intArrayOf(),
65 | ),
66 | Arguments.of(
67 | intArrayOf(4, 8, 15, 16, 23),
68 | 12,
69 | intArrayOf(0, 1),
70 | ),
71 | Arguments.of(
72 | intArrayOf(4, 8, 15, 16, 23),
73 | 39,
74 | intArrayOf(3, 4),
75 | ),
76 | Arguments.of(
77 | intArrayOf(2, 7, 11, 15),
78 | 9,
79 | intArrayOf(0, 1),
80 | ),
81 | Arguments.of(
82 | intArrayOf(3, 2, 4),
83 | 6,
84 | intArrayOf(1, 2),
85 | ),
86 | Arguments.of(
87 | intArrayOf(3, 3),
88 | 6,
89 | intArrayOf(0, 1),
90 | ),
91 | )
92 | }
93 | }
94 |
95 | class TwoSumBruteForceTest : TwoSumTest(twoSumBruteForce)
96 | class TwoSumTwoPassHashTableTest : TwoSumTest(twoSumTwoPassHashTable)
97 | class TwoSumOnePassHashTableTest : TwoSumTest(twoSumOnePassHashTable)
98 | class TwoSumOneHashMapTest : TwoSumTest(twoSumOneHashMap)
99 |
--------------------------------------------------------------------------------
/src/main/kotlin/dev/shtanko/algorithms/sorts/BubbleSorts.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 |
4 | * Copyright (c) 2022 Oleksii Shtanko
5 |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 |
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package dev.shtanko.algorithms.sorts
26 |
27 | import dev.shtanko.algorithms.extensions.swap
28 |
29 | /**
30 | * Bubble sort is a simple sorting algorithm that repeatedly steps through the list to be sorted, compares
31 | * each pair of adjacent items and swaps them if they are in the wrong order. The pass through the list is repeated
32 | * until no swaps are needed, which indicates that the list is sorted. The algorithm, which is a comparison sort,
33 | * is named for the way smaller or larger elements "bubble" to the top of the list. Although the algorithm is simple,
34 | * it is too slow and impractical for most problems even when compared to insertion sort. It can be practical
35 | * if the input is usually in sorted order but may occasionally have some out-of-order elements nearly in position.
36 | *
37 | * Worst-case performance: O(n^2)
38 | * Best-case performance: O(n)
39 | * Average performance: O(n^2)
40 | * Worst-case space complexity: O(1)
41 | */
42 | data object BubbleSort : Sortable {
43 | /**
44 | * Performs the bubble sort operation on the given array.
45 | *
46 | * @param arr The array to sort.
47 | * @param T The type of elements in the array, must be comparable.
48 | */
49 | override fun > invoke(arr: Array) {
50 | var exchanged: Boolean
51 |
52 | do {
53 | exchanged = false
54 | for (i in 1 until arr.size) {
55 | if (arr[i] < arr[i - 1]) {
56 | arr.swap(i, i - 1)
57 | exchanged = true
58 | }
59 | }
60 | } while (exchanged)
61 | }
62 | }
63 |
64 | /**
65 | * SimpleBubbleSort is a basic implementation of the bubble sort algorithm.
66 | * It iterates through the array multiple times, comparing adjacent elements and swapping them if they are out of order.
67 | * The algorithm continues this process until the array is sorted.
68 | *
69 | * Worst-case performance: O(n^2)
70 | * Best-case performance: O(n^2)
71 | * Average performance: O(n^2)
72 | * Worst-case space complexity: O(1)
73 | */
74 | data object SimpleBubbleSort : Sortable {
75 | /**
76 | * Performs the simple bubble sort operation on the given array.
77 | *
78 | * @param arr The array to sort.
79 | * @param T The type of elements in the array, must be comparable.
80 | */
81 | override fun > invoke(arr: Array) {
82 | for (i in 0 until arr.size - 1) {
83 | for (j in i + 1 until arr.size) {
84 | if (arr[i] > arr[j]) {
85 | arr.swap(i, j)
86 | }
87 | }
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/kotlin/dev/shtanko/algorithms/sorts/BottomUpMergeSort.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 |
4 | * Copyright (c) 2022 Oleksii Shtanko
5 |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 |
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package dev.shtanko.algorithms.sorts
26 |
27 | /**
28 | * Implementation: Iterative
29 | * Space Complexity: O(n)
30 | * Ease of Use: Natural fit for linked lists
31 | * Stability: Stable
32 | * Performance: O(n log n)
33 | * Memory Usage: O(n), no recursion stack
34 | */
35 | data object BottomUpMergeSort : Sortable {
36 | override fun > invoke(arr: Array) {
37 | val size = arr.size
38 | val tempArray = arr.copyOf()
39 |
40 | var width = 1
41 | while (width < size) {
42 | var i = 0
43 | while (i < size) {
44 | // Find the middle point
45 | val middle = kotlin.math.min(i + width, size)
46 | // Find the end of the current segment
47 | val end = kotlin.math.min(i + 2 * width, size)
48 | // Merge the sub-arrays array[i…middle-1] and array[middle…end-1] into tempArray
49 | merge(arr, tempArray, i, middle, end)
50 | i += 2 * width
51 | }
52 | // Copy the merged array back to the original array
53 | tempArray.copyInto(arr)
54 | width *= 2
55 | }
56 | }
57 |
58 | /**
59 | * Merge two sub-arrays of array[].
60 | *
61 | * @param array the array to be sorted
62 | * @param tempArray the temporary array used for merging
63 | * @param start the start index of the first sub-array
64 | * @param middle the end index of the first sub-array
65 | * @param end the end index of the second sub-array
66 | * @param the type of elements in the array
67 | * @return the merged array
68 | */
69 | private fun > merge(
70 | array: Array,
71 | tempArray: Array,
72 | start: Int,
73 | middle: Int,
74 | end: Int,
75 | ) {
76 | var i = start
77 | var j = middle
78 | var k = start
79 |
80 | // Merge the two sub-arrays into tempArray
81 | while (i < middle && j < end) {
82 | if (array[i] <= array[j]) {
83 | tempArray[k] = array[i]
84 | i++
85 | } else {
86 | tempArray[k] = array[j]
87 | j++
88 | }
89 | k++
90 | }
91 |
92 | // Copy remaining elements of the left half, if any
93 | while (i < middle) {
94 | tempArray[k] = array[i]
95 | i++
96 | k++
97 | }
98 |
99 | // Copy remaining elements of the right half, if any
100 | while (j < end) {
101 | tempArray[k] = array[j]
102 | j++
103 | k++
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/kotlin/dev/shtanko/algorithms/extensions/ArrayX.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 |
4 | * Copyright (c) 2022 Oleksii Shtanko
5 |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 |
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package dev.shtanko.algorithms.extensions
26 |
27 | /**
28 | * Swaps elements at the specified indices in the array.
29 | *
30 | * @param i The index of the first element to swap.
31 | * @param j The index of the second element to swap.
32 | */
33 | fun Array.swap(
34 | i: Int,
35 | j: Int,
36 | ) {
37 | val temp = this[i]
38 | this[i] = this[j]
39 | this[j] = temp
40 | }
41 |
42 | /**
43 | * Swaps elements at the specified indices in the IntArray.
44 | *
45 | * @param i The index of the first element to swap.
46 | * @param j The index of the second element to swap.
47 | */
48 | fun IntArray.swap(
49 | i: Int,
50 | j: Int,
51 | ) {
52 | val tmp = this[i]
53 | this[i] = this[j]
54 | this[j] = tmp
55 | }
56 |
57 | /**
58 | * Reverses the elements in the array in place.
59 | */
60 | fun Array.reverse() {
61 | val arraySize = this.size
62 | for (startIndex in 0 until arraySize / 2) {
63 | this.swap(startIndex, arraySize - 1 - startIndex)
64 | }
65 | }
66 |
67 | /**
68 | * Reverses the elements in the array in place using two pointers.
69 | */
70 | fun Array.reverse2() {
71 | var i = 0
72 | var j = size - 1
73 | while (i < j) {
74 | swap(i, j)
75 | i++
76 | j--
77 | }
78 | }
79 |
80 | /**
81 | * Flips the elements in the array between the specified indices in place.
82 | *
83 | * @param leftIndex The starting index (inclusive) of the portion to flip.
84 | * @param rightIndex The ending index (inclusive) of the portion to flip.
85 | */
86 | fun Array.flip(
87 | leftIndex: Int,
88 | rightIndex: Int,
89 | ) {
90 | var left = leftIndex
91 | var right = rightIndex
92 | while (left <= right) {
93 | swap(left++, right--)
94 | }
95 | }
96 |
97 | /**
98 | * Returns the second element of the IntArray.
99 | *
100 | * @return The second element of the IntArray.
101 | * @throws NoSuchElementException if the array is empty.
102 | */
103 | fun IntArray.second(): Int {
104 | if (isEmpty()) {
105 | throw NoSuchElementException("Array is empty.")
106 | }
107 | return this[1]
108 | }
109 |
110 | /**
111 | * Finds the index of the minimum element in the array starting from the
112 | * specified index.
113 | *
114 | * @param i The starting index from which to search for the minimum element.
115 | * @return The index of the minimum element found in the array starting from the
116 | * specified index.
117 | */
118 | fun > Array.findMinimumIndex(i: Int): Int {
119 | var min = i
120 | for (j in i + 1 until this.size) {
121 | if (this[j] < this[min]) {
122 | min = j
123 | }
124 | }
125 | return min
126 | }
127 |
--------------------------------------------------------------------------------