├── .gitignore
├── .idea
├── .gitignore
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── kotlinc.xml
├── libraries
│ └── KotlinJavaRuntime.xml
├── misc.xml
├── modules.xml
├── uiDesigner.xml
└── vcs.xml
├── Data Structures and Algorithms.iml
├── LICENSE.md
├── README.md
├── dsa-kotlin-banner.png
└── src
├── algorithms
├── README.md
├── recursion
│ ├── README.md
│ ├── factorial
│ │ └── Factorial.kt
│ ├── fibonacci
│ │ └── Fibonacci.kt
│ └── reverse_string
│ │ └── ReverseString.kt
├── searching
│ ├── bfs
│ │ └── README.md
│ ├── binary_search
│ │ ├── BinarySearch.kt
│ │ └── README.md
│ ├── dfs
│ │ └── README.md
│ └── linear_search
│ │ ├── LinearSearch.kt
│ │ └── README.md
└── sorting
│ ├── bubble_sort
│ ├── BubbleSort.kt
│ └── README.md
│ ├── insertion_sort
│ ├── InsertionSort.kt
│ └── README.md
│ ├── merge_sort
│ ├── MergeSort.kt
│ └── README.md
│ ├── quick_sort
│ ├── QuickSort.kt
│ └── README.md
│ └── selection_sort
│ ├── README.md
│ └── SelectionSort.kt
├── data_structures
├── README.md
├── arrays
│ ├── README.md
│ ├── implementation
│ │ └── DynamicArray.kt
│ ├── merge_sorted_arrays
│ │ └── MergeSortedArrays.kt
│ └── reverse_string
│ │ └── ReverseString.kt
├── graphs
│ ├── Graph.kt
│ └── README.md
├── hash_tables
│ ├── README.md
│ ├── first_recurring_character
│ │ └── FirstRecurring.kt
│ └── implementation
│ │ ├── HashTable.kt
│ │ └── KeyValue.kt
├── linked_lists
│ ├── doubly_linked_list
│ │ ├── DoublyLinkedList.kt
│ │ └── Node.kt
│ └── singly_linked_list
│ │ ├── Node.kt
│ │ └── SinglyLinkedList.kt
├── queues
│ ├── queue_using_linked_list
│ │ ├── Node.kt
│ │ └── Queue.kt
│ └── queue_using_stacks
│ │ └── Queue.kt
├── stacks
│ ├── stack_using_array
│ │ └── Stack.kt
│ └── stack_using_linked_list
│ │ ├── Node.kt
│ │ └── Stack.kt
└── trees
│ ├── binary_search_tree
│ ├── BinarySearchTree.kt
│ ├── BinarySearchTreeNoComments.kt
│ └── Node.kt
│ ├── priority_queue
│ ├── Node.kt
│ └── PriorityQueue.kt
│ └── trie
│ ├── Node.kt
│ └── Trie.kt
└── dynamic_programming
├── README.md
├── dynamic_fibonacci
└── DynamicFibonacci.kt
└── memoization
└── Memoization.kt
/.gitignore:
--------------------------------------------------------------------------------
1 | # Project exclude paths
2 | /out/
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/libraries/KotlinJavaRuntime.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/uiDesigner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Data Structures and Algorithms.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Asror Abdurakhmanov
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | ## Data Structures and Algorithms in Kotlin
3 | This is a GitHub repository containing implementations and explanations of various data structures[⌝](https://en.wikipedia.org/wiki/Data_structure) and algorithms[⌝](https://en.wikipedia.org/wiki/Algorithm) in Kotlin programming language. The repository covers a wide range of topics including arrays, linked lists, stacks, queues, trees, sorting algorithms, searching algorithms, and dynamic programming. Each implementation is accompanied by clear and concise code comments explaining the purpose and functionality of the code. The repository provides a great resource for anyone looking to learn or improve their understanding of data structures and algorithms using Kotlin.
4 |
5 | ### Overview
6 | - [Data Structures](https://github.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/tree/master/src/data_structures)
7 | - Arrays[⌝](https://github.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/tree/master/src/data_structures/arrays)
8 | - Hash Tables[⌝](https://github.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/tree/master/src/data_structures/hash_tables)
9 | - Linked Lists[⌝](https://github.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/tree/master/src/data_structures/linked_lists)
10 | - Stacks[⌝](https://github.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/tree/master/src/data_structures/stacks)
11 | - Queues[⌝](https://github.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/tree/master/src/data_structures/queues)
12 | - Trees[⌝](https://github.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/tree/master/src/data_structures/trees)
13 | - Graphs[⌝](https://github.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/tree/master/src/data_structures/graphs)
14 | - [Algorithms](https://github.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/tree/master/src/algorithms)
15 | - Recursion[⌝](https://github.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/tree/master/src/algorithms/recursion)
16 | - Sorting[⌝](https://github.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/tree/master/src/algorithms/sorting)
17 | - Bubble Sort
18 | - Selection Sort
19 | - Insertion Sort
20 | - Merge Sort
21 | - Quick Sort
22 | - Searching[⌝](https://github.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/tree/master/src/algorithms/searching)
23 | - Linear Search
24 | - Binary Search
25 | - BFS
26 | - DFS
27 | - [Dynamic Programming](https://github.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/tree/master/src/dynamic_programming)
28 | - Memoization[⌝](https://github.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/blob/2daef674620f7deb2155de5a03d3e861fc2739fa/src/dynamic_programming/memoization)
29 |
30 | ### Get started
31 | 1. Clone or download the repository and open it on your favorite IDE. (Recommended IDE: [IntelliJ IDEA](https://www.jetbrains.com/idea/download/))
32 | 2. Checkout the implementation and explanation of various data structures and algorithms and try them out.
33 |
--------------------------------------------------------------------------------
/dsa-kotlin-banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/cd9746d02b34b54dd0cf8c8dacc2fb91d2a3cc07/dsa-kotlin-banner.png
--------------------------------------------------------------------------------
/src/algorithms/README.md:
--------------------------------------------------------------------------------
1 | ### Algorithms overview
2 |
3 | - Recursion
4 | - Factorial (problem)
5 | - Fibonacci (problem)
6 | - Reverse string (problem)
7 | - Sorting
8 | - Bubble Sort
9 | - Selection Sort
10 | - Insertion Sort
11 | - Merge Sort
12 | - Quick Sort
13 | - Searching
14 | - Linear Search
15 | - Binary Search
16 | - BFS
17 | - DFS
18 |
19 | ### Algorithms definition
20 |
21 | Algorithms are a set of instructions or a step-by-step procedure for solving a problem or performing a task. They are an essential part of computer science and programming and are used to perform various computational tasks, such as sorting data, searching for information, and solving mathematical problems.
--------------------------------------------------------------------------------
/src/algorithms/recursion/README.md:
--------------------------------------------------------------------------------
1 | ### Recursion
2 |
3 | Recursion is a programming technique where a function calls itself to solve a problem. Recursion is commonly used to
4 | solve problems that can be broken down into smaller, simpler subproblems.
5 |
6 | In Kotlin, a recursive function is defined like any other function, but it calls itself within its own body. Here's an
7 | example of a Kotlin function that uses recursion to calculate the factorial of a number:
8 |
9 | ```kotlin
10 | fun findFactorialRecursive(number: Int): Int {
11 | return if (number < 2)
12 | 1
13 | else
14 | number * findFactorialRecursive(number - 1)
15 | }
16 | ```
17 |
18 | The `if` statement checks if the `number` is less than 2. If it is, the function returns 1, as the factorial of 0 and 1
19 | is 1. If the `number` is greater than or equal to 2, the function moves to the `else` block.
20 |
21 | In the `else` block, the function multiplies the `number` with the factorial of `number-1`. This is done by calling the
22 | same function recursively with the parameter `number-1`. The function keeps calling itself recursively with decreasing
23 | values of `number` until it reaches 1, at which point the base case is triggered and the recursion stops.
24 |
25 | For example, if `number` is 4, the function calculates `4*3*2*1` recursively. It first multiplies `4` with the result of
26 | calling `findFactorialRecursive(3)`. The `findFactorialRecursive` function then multiplies `3` with the result of
27 | calling `findFactorialRecursive(2)`, and so on until it reaches the base case of `findFactorialRecursive(1)`, which
28 | returns `1`. The multiplication chain is then complete and the final result of `4*3*2*1` is returned by the original
29 | call to `findFactorialRecursive(4)`.
--------------------------------------------------------------------------------
/src/algorithms/recursion/factorial/Factorial.kt:
--------------------------------------------------------------------------------
1 | package algorithms.recursion.factorial
2 |
3 | class Factorial {
4 |
5 | /**
6 | * Returns the factorial of the given integer using a recursive approach.
7 | *
8 | * @param number the integer to calculate the factorial of
9 | * @return the factorial of the given integer
10 | */
11 | fun findFactorialRecursive(number: Int): Int {
12 | return if (number < 2)
13 | 1
14 | else
15 | number * findFactorialRecursive(number - 1)
16 | }
17 |
18 | /**
19 | * Returns the factorial of the given integer using an iterative approach.
20 | *
21 | * @param number the integer to calculate the factorial of
22 | * @return the factorial of the given integer
23 | */
24 | fun findFactorialIterative(number: Int): Int {
25 | return if (number < 2) {
26 | 1
27 | } else {
28 | var answer = 1
29 | for (i in 2..number) {
30 | answer *= i
31 | }
32 | answer
33 | }
34 | }
35 | }
36 |
37 | fun main() {
38 |
39 | val factorial = Factorial()
40 | println(factorial.findFactorialRecursive(5))
41 | println(factorial.findFactorialIterative(5))
42 | }
--------------------------------------------------------------------------------
/src/algorithms/recursion/fibonacci/Fibonacci.kt:
--------------------------------------------------------------------------------
1 | package algorithms.recursion.fibonacci
2 |
3 | class Fibonacci {
4 |
5 | /**
6 | * Returns the nth number in the Fibonacci sequence using a recursive approach.
7 | *
8 | * @param n the position of the number to retrieve (starting from 0)
9 | * @return the nth number in the Fibonacci sequence
10 | */
11 | fun fibonacciRecursive(n: Int): Int {
12 | if (n == 0) return 0
13 | else if (n == 1 || n == 2) return 1
14 | return fibonacciRecursive(n - 1) + fibonacciRecursive(n - 2)
15 | }
16 |
17 | /**
18 | * Returns the nth number in the Fibonacci sequence using an iterative approach.
19 | *
20 | * @param n the position of the number to retrieve (starting from 0)
21 | * @return the nth number in the Fibonacci sequence
22 | */
23 | fun fibonacciIterative(n: Int): Int {
24 | return if (n == 0) {
25 | 0
26 | } else if (n == 1 || n == 2) {
27 | 1
28 | } else {
29 | val arr = intArrayOf(1, 1)
30 | for (i in 3..n) {
31 | val temp = arr[1]
32 | arr[1] = arr[0] + arr[1]
33 | arr[0] = temp
34 | }
35 | arr[1]
36 | }
37 | }
38 | }
39 |
40 | fun main() {
41 |
42 | val fibonacci = Fibonacci()
43 | println(fibonacci.fibonacciRecursive(5))
44 | println(fibonacci.fibonacciIterative(5))
45 | }
--------------------------------------------------------------------------------
/src/algorithms/recursion/reverse_string/ReverseString.kt:
--------------------------------------------------------------------------------
1 | package algorithms.recursion.reverse_string
2 |
3 | class ReverseString {
4 |
5 | /**
6 | * Returns the reverse of the given string using a recursive approach.
7 | *
8 | * @param str the string to reverse
9 | * @return the reverse of the given string
10 | */
11 | fun reverseStringRecursive(str: String): String {
12 | return if (str == "")
13 | ""
14 | else
15 | reverseStringRecursive(str.substring(1)) + str[0]
16 | }
17 |
18 | /**
19 | * Returns the reverse of the given string using an iterative approach.
20 | *
21 | * @param str the string to reverse
22 | * @return the reverse of the given string
23 | */
24 | fun reverseStringIterative(str: String): String {
25 | val charArray = str.toCharArray()
26 | for (i in 0 until charArray.size / 2) {
27 | val temp = charArray[i]
28 | charArray[i] = charArray[charArray.size - 1 - i]
29 | charArray[charArray.size - 1 - i] = temp
30 | }
31 | return String(charArray)
32 | }
33 | }
34 |
35 | fun main() {
36 |
37 | val reverse = ReverseString()
38 | println(reverse.reverseStringRecursive("yoyo mastery"))
39 | println(reverse.reverseStringIterative("yoyo mastery"))
40 | }
--------------------------------------------------------------------------------
/src/algorithms/searching/bfs/README.md:
--------------------------------------------------------------------------------
1 | ### Breadth-first search
2 |
3 | You can find [implementation of BFS](https://github.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/blob/master/src/data_structures/trees/binary_search_tree/BinarySearchTree.kt) in data structures section:
4 | `src/data_structures/trees/binary_search_tree/BinarySearchTree.kt`
--------------------------------------------------------------------------------
/src/algorithms/searching/binary_search/BinarySearch.kt:
--------------------------------------------------------------------------------
1 | package algorithms.searching.binary_search
2 |
3 | class BinarySearch {
4 |
5 | /**
6 | * Performs a binary search on an array of integers to find the index of a specified key.
7 | *
8 | * @param arr the array to search
9 | * @param key the value to search for
10 | * @return a message indicating whether the element was found and its index, or that it was not found
11 | */
12 | fun binarySearch(arr: IntArray, key: Int): String {
13 | var first = 0
14 | var last = arr.size - 1
15 | var middle = (first + last) / 2
16 | while (first <= last) {
17 | when {
18 | arr[middle] < key -> {
19 | first = middle + 1
20 | }
21 | arr[middle] == key -> {
22 | return "Element found at index $middle"
23 | }
24 | else -> {
25 | last = middle - 1
26 | }
27 | }
28 | middle = (first + last) / 2
29 | }
30 | return "Element not found!"
31 | }
32 | }
33 |
34 | fun main() {
35 |
36 | val binarySearch = BinarySearch()
37 |
38 | // Note: Binary search works only with sorted arrays.
39 | val array = intArrayOf(10, 25, 32, 45, 55, 68)
40 | val result = binarySearch.binarySearch(array, 55)
41 | println(result)
42 |
43 | val result2 = binarySearch.binarySearch(array, 100)
44 | println(result2)
45 | }
--------------------------------------------------------------------------------
/src/algorithms/searching/binary_search/README.md:
--------------------------------------------------------------------------------
1 | ### Binary search
2 |
3 | This function performs a binary search on a sorted array of integers to find the index of a specified key. The algorithm
4 | works by repeatedly dividing the array in half and discarding the half that the key cannot be in, until the key is found
5 | or the entire array has been searched.
6 |
7 | ```kotlin
8 | fun binarySearch(arr: IntArray, key: Int): String {
9 | // Initialize first, last, and middle indexes
10 | var first = 0
11 | var last = arr.size - 1
12 | var middle = (first + last) / 2
13 |
14 | // Loop until the first index is greater than the last index
15 | while (first <= last) {
16 | when {
17 | // If the middle element is less than the key, update the first index to middle + 1
18 | // This means that the key is in the right half of the array
19 | arr[middle] < key -> {
20 | first = middle + 1
21 | }
22 | // If the middle element is equal to the key, return a message indicating that it was found
23 | // and its index
24 | arr[middle] == key -> {
25 | return "Element found at index $middle"
26 | }
27 | // If the middle element is greater than the key, update the last index to middle - 1
28 | // This means that the key is in the left half of the array
29 | else -> {
30 | last = middle - 1
31 | }
32 | }
33 | // Recalculate the middle index based on the updated first and last indexes
34 | middle = (first + last) / 2
35 | }
36 | // If the loop completes and the key is not found, return a message indicating that it was not found
37 | return "Element not found!"
38 | }
39 | ```
--------------------------------------------------------------------------------
/src/algorithms/searching/dfs/README.md:
--------------------------------------------------------------------------------
1 | ### Depth-first search
2 |
3 | You can find [implementation of DFS](https://github.com/abdurakhmonoff/data-structures-and-algorithms-kotlin/blob/master/src/data_structures/trees/binary_search_tree/BinarySearchTree.kt) in data structures section:
4 | `src/data_structures/trees/binary_search_tree/BinarySearchTree.kt`
--------------------------------------------------------------------------------
/src/algorithms/searching/linear_search/LinearSearch.kt:
--------------------------------------------------------------------------------
1 | package algorithms.searching.linear_search
2 |
3 | class LinearSearch {
4 |
5 | /**
6 | * Performs a linear search on an array of integers to find the index of a specified key.
7 | *
8 | * @param arr the array to search
9 | * @param key the value to search for
10 | * @return the index of the key if it is found, or -1 if it is not found
11 | */
12 | fun linearSearch(arr: IntArray, key: Int): Int {
13 | for (i in arr.indices) {
14 | if (arr[i] == key) {
15 | return i
16 | }
17 | }
18 | return -1
19 | }
20 | }
21 |
22 | fun main() {
23 |
24 | val linearSearch = LinearSearch()
25 | val arr = intArrayOf(12, 45, 69, 78, 89, 54)
26 | val answer = linearSearch.linearSearch(arr, 69)
27 | println(answer)
28 | }
--------------------------------------------------------------------------------
/src/algorithms/searching/linear_search/README.md:
--------------------------------------------------------------------------------
1 | ### Linear search
2 |
3 | This function performs a linear search on an array of integers to find the index of a specified key. The algorithm works
4 | by iterating through each element in the array and comparing it to the key until the key is found or the entire array
5 | has been searched.
6 |
7 | ```kotlin
8 | fun linearSearch(arr: IntArray, key: Int): Int {
9 | // Loop through each element in the array
10 | for (i in arr.indices) {
11 | // If the current element is equal to the key, return its index
12 | if (arr[i] == key) {
13 | return i
14 | }
15 | }
16 | // If the loop completes without finding the key, return -1
17 | return -1
18 | }
19 | ```
--------------------------------------------------------------------------------
/src/algorithms/sorting/bubble_sort/BubbleSort.kt:
--------------------------------------------------------------------------------
1 | package algorithms.sorting.bubble_sort
2 |
3 | /**
4 | * Performs a bubble sort on an array of integers to sort it in ascending order.
5 | *
6 | * @param array the array to sort
7 | */
8 | fun bubbleSort(array: IntArray) {
9 | // Outer loop iterates over the array indices
10 | for (i in array.indices) {
11 | // Inner loop compares adjacent elements of the array and swaps them if
12 | // they are in the wrong order
13 | for (j in 0 until array.size - 1) {
14 | // If the current element is greater than the next element, swap them
15 | if (array[j] > array[j + 1]) {
16 | val temp = array[j]
17 | array[j] = array[j + 1]
18 | array[j + 1] = temp
19 | }
20 | }
21 | }
22 | }
23 |
24 | fun main() {
25 |
26 | val numbers = intArrayOf(99, 44, 6, 2, 1, 5, 63, 87, 283, 4, 0)
27 | bubbleSort(numbers)
28 | println(numbers.contentToString())
29 | }
--------------------------------------------------------------------------------
/src/algorithms/sorting/bubble_sort/README.md:
--------------------------------------------------------------------------------
1 | ### Bubble sort
2 |
3 | This code implements a bubble sort algorithm for an array of integers. The algorithm works by iterating over
4 | the array and comparing adjacent elements. If the adjacent elements are not in the correct order, they are swapped. This
5 | process is repeated until the entire array is sorted. The outer loop iterates over the array indices, while the inner
6 | loop compares adjacent elements of the array and swaps them if they are in the wrong order.
7 |
8 | ```kotlin
9 | fun bubbleSort(array: IntArray) {
10 | // Outer loop iterates over the array indices
11 | for (i in array.indices) {
12 | // Inner loop compares adjacent elements of the array and swaps them if
13 | // they are in the wrong order
14 | for (j in 0 until array.size - 1) {
15 | // If the current element is greater than the next element, swap them
16 | if (array[j] > array[j + 1]) {
17 | val temp = array[j]
18 | array[j] = array[j + 1]
19 | array[j + 1] = temp
20 | }
21 | }
22 | }
23 | }
24 | ```
--------------------------------------------------------------------------------
/src/algorithms/sorting/insertion_sort/InsertionSort.kt:
--------------------------------------------------------------------------------
1 | package algorithms.sorting.insertion_sort
2 |
3 | /**
4 | * Performs an insertion sort on an ArrayList of integers to sort it in ascending order.
5 | *
6 | * @param array the ArrayList to sort
7 | */
8 | fun insertionSort(array: ArrayList) {
9 | // Iterate over the indices of the input array
10 | for (i in array.indices) {
11 | // If the current number is less than or equal to the first number, insert it at the beginning of the array
12 | if (array[i] <= array[0]) {
13 | array.add(0, array.removeAt(i))
14 | } else {
15 | // If the current number is less than the previous number, find the correct position to insert it
16 | if (array[i] < array[i - 1]) {
17 | // Iterate over the array from the second number to the current number
18 | for (j in 1 until i) {
19 | // If the current number is less than the j-th number, insert it at that position
20 | if (array[i] < array[j]) {
21 | array.add(j, array.removeAt(i))
22 | break
23 | }
24 | }
25 | }
26 | }
27 | }
28 | }
29 |
30 | fun main() {
31 |
32 | val numbers = ArrayList(listOf(99, 44, 6, 2, 1, 5, 63, 87, 283, 4, 0))
33 | insertionSort(numbers)
34 | println(numbers)
35 | }
--------------------------------------------------------------------------------
/src/algorithms/sorting/insertion_sort/README.md:
--------------------------------------------------------------------------------
1 | ### Insertion sort
2 |
3 | This code implements an insertion sort algorithm for an ArrayList of integers. Insertion sort is a simple sorting
4 | algorithm that sorts an array by repeatedly shifting elements that are greater than
5 | the current element to be sorted one position ahead of their current position. The algorithm works by iterating over the
6 | input array, and at each iteration, it inserts the current element into its correct position in the sorted portion of
7 | the array that precedes it.
8 |
9 | ```kotlin
10 | fun insertionSort(array: ArrayList) {
11 | // Iterate over the indices of the input array
12 | for (i in array.indices) {
13 | // If the current number is less than or equal to the first number, insert it at the beginning of the array
14 | if (array[i] <= array[0]) {
15 | array.add(0, array.removeAt(i))
16 | } else {
17 | // If the current number is less than the previous number, find the correct position to insert it
18 | if (array[i] < array[i - 1]) {
19 | // Iterate over the array from the second number to the current number
20 | for (j in 1 until i) {
21 | // If the current number is less than the j-th number, insert it at that position
22 | if (array[i] < array[j]) {
23 | array.add(j, array.removeAt(i))
24 | break
25 | }
26 | }
27 | }
28 | }
29 | }
30 | }
31 | ```
--------------------------------------------------------------------------------
/src/algorithms/sorting/merge_sort/MergeSort.kt:
--------------------------------------------------------------------------------
1 | package algorithms.sorting.merge_sort
2 |
3 | /**
4 | * Implementation of the merge sort algorithm for sorting a list of integers in ascending order.
5 | */
6 | class MergeSort {
7 |
8 | /**
9 | * Recursively sorts the given list by dividing it into halves and merging them.
10 | *
11 | * @param array the list to sort
12 | * @return the sorted list
13 | */
14 | fun mergeSort(array: List): List {
15 | // Base case: if array has only one number, it is already sorted
16 | if (array.size == 1) {
17 | return array
18 | }
19 | // Divide the array into two halves and recursively sort each half
20 | val left = array.subList(0, array.size / 2)
21 | val right = array.subList(array.size / 2, array.size)
22 | return merge(mergeSort(left), mergeSort(right))
23 | }
24 |
25 | /**
26 | * Merges two sorted lists into a single sorted list.
27 | *
28 | * @param left the first sorted list
29 | * @param right the second sorted list
30 | * @return the merged sorted list
31 | */
32 | private fun merge(left: List, right: List): List {
33 | val result = ArrayList()
34 | var leftIndex = 0
35 | var rightIndex = 0
36 | // Iterate through both lists, comparing the numbers and adding the smaller one to the result list
37 | while (leftIndex < left.size && rightIndex < right.size) {
38 | if (left[leftIndex] < right[rightIndex]) {
39 | result.add(left[leftIndex])
40 | leftIndex++
41 | } else {
42 | result.add(right[rightIndex])
43 | rightIndex++
44 | }
45 | }
46 | // Add any remaining numbers from the left and right lists
47 | val leftRemaining = left.subList(leftIndex, left.size)
48 | val rightRemaining = right.subList(rightIndex, right.size)
49 | result.addAll(leftRemaining)
50 | result.addAll(rightRemaining)
51 | return result
52 | }
53 | }
54 |
55 | fun main() {
56 |
57 | val mergeSort = MergeSort()
58 | val numbers = ArrayList(listOf(99, 44, 6, 2, 1, 5, 63, 87, 283, 4, 0))
59 | println(mergeSort.mergeSort(numbers))
60 | }
--------------------------------------------------------------------------------
/src/algorithms/sorting/merge_sort/README.md:
--------------------------------------------------------------------------------
1 | ### Merge sort
2 |
3 | Merge Sort is a sorting algorithm that utilizes the divide-and-conquer strategy. The basic idea behind this algorithm is
4 | to divide the input array into two halves, sort them separately, and then merge them into a single sorted output array.
5 | It achieves this by recursively dividing the input array into smaller sub-arrays until the base case of a single element
6 | array is reached, which is trivially sorted. The sub-arrays are then merged together in a series of comparisons that
7 | result in a new sorted array.
8 |
9 | ```kotlin
10 | class MergeSort {
11 |
12 | fun mergeSort(array: List): List {
13 | // Base case: if array has only one number, it is already sorted
14 | if (array.size == 1) {
15 | return array
16 | }
17 | // Divide the array into two halves and recursively sort each half
18 | val left = array.subList(0, array.size / 2)
19 | val right = array.subList(array.size / 2, array.size)
20 | return merge(mergeSort(left), mergeSort(right))
21 | }
22 |
23 | private fun merge(left: List, right: List): List {
24 | val result = ArrayList()
25 | var leftIndex = 0
26 | var rightIndex = 0
27 | // Iterate through both lists, comparing the numbers and adding the smaller one to the result list
28 | while (leftIndex < left.size && rightIndex < right.size) {
29 | if (left[leftIndex] < right[rightIndex]) {
30 | result.add(left[leftIndex])
31 | leftIndex++
32 | } else {
33 | result.add(right[rightIndex])
34 | rightIndex++
35 | }
36 | }
37 | // Add any remaining numbers from the left and right lists
38 | val leftRemaining = left.subList(leftIndex, left.size)
39 | val rightRemaining = right.subList(rightIndex, right.size)
40 | result.addAll(leftRemaining)
41 | result.addAll(rightRemaining)
42 | return result
43 | }
44 | }
45 | ```
--------------------------------------------------------------------------------
/src/algorithms/sorting/quick_sort/QuickSort.kt:
--------------------------------------------------------------------------------
1 | package algorithms.sorting.quick_sort
2 |
3 | /**
4 | * Implementation of the quick sort algorithm for sorting a list of integers in ascending order.
5 | */
6 | class QuickSort {
7 |
8 | /**
9 | * Sorts an array of integers in ascending order using QuickSort algorithm.
10 | *
11 | * @param arr the array to be sorted.
12 | * @param low the starting index of the array.
13 | * @param high the ending index of the array.
14 | */
15 | fun quickSort(arr: IntArray, low: Int, high: Int) {
16 | if (low < high) {
17 | // Find partition index
18 | val pIndex = partition(arr, low, high)
19 | // Recursively sort elements before and after partition index
20 | quickSort(arr, low, pIndex - 1)
21 | quickSort(arr, pIndex + 1, high)
22 | }
23 | }
24 |
25 | /**
26 | * Partitions the array into two sub-arrays around the pivot element.
27 | *
28 | * @param arr the array to be partitioned.
29 | * @param low the starting index of the array.
30 | * @param high the ending index of the array.
31 | * @return the index of the pivot element after partitioning.
32 | */
33 | private fun partition(arr: IntArray, low: Int, high: Int): Int {
34 | val pivot = arr[high]
35 | var i = low - 1
36 | // Iterate through numbers from low to high-1
37 | for (j in low until high) {
38 | if (arr[j] <= pivot) {
39 | i++
40 | // Swap arr[i] and arr[j]
41 | val temp = arr[i]
42 | arr[i] = arr[j]
43 | arr[j] = temp
44 | }
45 | }
46 | // Place pivot at correct position in array
47 | val temp = arr[i + 1]
48 | arr[i + 1] = arr[high]
49 | arr[high] = temp
50 | // Return partition index
51 | return i + 1
52 | }
53 |
54 | /**
55 | * Prints the elements of the array.
56 | *
57 | * @param arr the array to be printed.
58 | */
59 | fun printArray(arr: IntArray) {
60 | for (value in arr) print("$value ")
61 | println()
62 | }
63 | }
64 |
65 | fun main() {
66 |
67 | val numbers = intArrayOf(99, 44, 6, 2, 1, 5, 63, 87, 283, 4, 0)
68 | val quickSort = QuickSort()
69 | quickSort.quickSort(numbers, 0, numbers.size - 1)
70 | quickSort.printArray(numbers)
71 | }
--------------------------------------------------------------------------------
/src/algorithms/sorting/quick_sort/README.md:
--------------------------------------------------------------------------------
1 | ### Quick sort
2 |
3 | Quick sort is a sorting algorithm that uses the divide-and-conquer approach to sort an input array. It selects a pivot
4 | element from the array and partitions the array into two sub-arrays: one with elements smaller than the pivot and the
5 | other with elements greater than or equal to the pivot. This process is then recursively applied to the two sub-arrays
6 | until they contain only one element. The base case of a single element array is trivially sorted. The sub-arrays are
7 | then combined by concatenating the sorted sub-arrays with the pivot element in between them to produce the sorted output
8 | array.
9 |
10 | ```kotlin
11 | class QuickSort {
12 |
13 | fun quickSort(arr: IntArray, low: Int, high: Int) {
14 | if (low < high) {
15 | // Find partition index
16 | val pIndex = partition(arr, low, high)
17 | // Recursively sort elements before and after partition index
18 | quickSort(arr, low, pIndex - 1)
19 | quickSort(arr, pIndex + 1, high)
20 | }
21 | }
22 |
23 | private fun partition(arr: IntArray, low: Int, high: Int): Int {
24 | val pivot = arr[high]
25 | var i = low - 1
26 | // Iterate through numbers from low to high-1
27 | for (j in low until high) {
28 | if (arr[j] <= pivot) {
29 | i++
30 | // Swap arr[i] and arr[j]
31 | val temp = arr[i]
32 | arr[i] = arr[j]
33 | arr[j] = temp
34 | }
35 | }
36 | // Place pivot at correct position in array
37 | val temp = arr[i + 1]
38 | arr[i + 1] = arr[high]
39 | arr[high] = temp
40 | // Return partition index
41 | return i + 1
42 | }
43 | }
44 | ```
--------------------------------------------------------------------------------
/src/algorithms/sorting/selection_sort/README.md:
--------------------------------------------------------------------------------
1 | ### Selection sort
2 |
3 | Selection sort is a simple sorting algorithm that works by repeatedly finding the smallest element from an unsorted part
4 | of the array and swapping it with the first element of the unsorted part. This process is repeated until the entire
5 | array is sorted. It is an in-place algorithm and is not recursive, making it easy to implement and understand.
6 |
7 | ```kotlin
8 | fun selectionSort(array: IntArray) {
9 | for (i in array.indices) {
10 | // Find the index of the smallest number in the unsorted portion of the array
11 | var smallest = i
12 | for (j in i until array.size) {
13 | if (array[j] < array[smallest]) {
14 | smallest = j
15 | }
16 | }
17 | // Swap the smallest number with the first number in the unsorted portion of the array
18 | val temp = array[i]
19 | array[i] = array[smallest]
20 | array[smallest] = temp
21 | }
22 | }
23 | ```
--------------------------------------------------------------------------------
/src/algorithms/sorting/selection_sort/SelectionSort.kt:
--------------------------------------------------------------------------------
1 | package algorithms.sorting.selection_sort
2 |
3 | /**
4 | * Sorts an array of integers using the selection sort algorithm.
5 | *
6 | * @param array the array to sort
7 | * @return the sorted array
8 | */
9 | fun selectionSort(array: IntArray): IntArray {
10 | for (i in array.indices) {
11 | // Find the index of the smallest number in the unsorted portion of the array
12 | var smallest = i
13 | for (j in i until array.size) {
14 | if (array[j] < array[smallest]) {
15 | smallest = j
16 | }
17 | }
18 | // Swap the smallest number with the first number in the unsorted portion of the array
19 | val temp = array[i]
20 | array[i] = array[smallest]
21 | array[smallest] = temp
22 | }
23 | return array
24 | }
25 |
26 | fun main() {
27 |
28 | val numbers = intArrayOf(99, 44, 6, 2, 1, 5, 63, 87, 283, 4, 0)
29 | println(selectionSort(numbers).contentToString())
30 | }
--------------------------------------------------------------------------------
/src/data_structures/README.md:
--------------------------------------------------------------------------------
1 | ### Data structures overview
2 |
3 | - Arrays
4 | - Implementation (problem)
5 | - Merge sorted arrays (problem)
6 | - Reverse string (problem)
7 | - Hash Tables
8 | - First recurring character (problem)
9 | - Implementation (problem)
10 | - Linked Lists
11 | - Doubly linked list
12 | - Singly linked list
13 | - Stacks
14 | - Stack using array (problem)
15 | - Stack using linked list (problem)
16 | - Queues
17 | - Queue using linked list (problem)
18 | - Queue using stacks (problem)
19 | - Trees
20 | - Binary search tree
21 | - Priority queue
22 | - Trie
23 | - Graphs
24 |
25 | ### Data structures definition
26 |
27 | Data structures refer to a way of organizing and storing data in a computer program, which can be used to efficiently access and manipulate the data. A variety of data structures exist, each designed to meet different needs and perform different operations.
--------------------------------------------------------------------------------
/src/data_structures/arrays/README.md:
--------------------------------------------------------------------------------
1 | ### Arrays
2 |
3 | An array is a fundamental data structure in computer programming that allows for efficient storage and retrieval of a
4 | collection of elements of the same type. It is a contiguous block of memory, where each element is accessed by its
5 | index. The index is an integer that represents the position of the element in the array, starting from 0. Arrays can be
6 | used to store primitive data types such as integers, characters, and booleans, as well as more complex objects such as
7 | strings and custom data types. The key advantage of arrays is their constant-time access to individual elements, which
8 | allows for fast retrieval and modification of data. However, the size of an array is fixed at creation time, so resizing
9 | requires creating a new array and copying the elements, which can be time-consuming and memory-intensive. Here's how we
10 | can implement an array that can dynamically resize itself as needed:
11 |
12 | ```kotlin
13 | class DynamicArray(
14 | private var array: Array = arrayOfNulls(1),
15 | private var capacity: Int = 1,
16 | var length: Int = 0
17 | ) {
18 |
19 | fun get(index: Int): String? {
20 | return if (index > -1 && index < length) array[index] else "IndexOutOfBounds"
21 | }
22 |
23 | fun push(string: String) {
24 | if (length == capacity) {
25 | val tempArray = arrayOfNulls(2 * capacity)
26 | for (i in array.indices) {
27 | tempArray[i] = array[i]
28 | }
29 | array = tempArray
30 | capacity *= 2
31 | }
32 | array[length] = string
33 | length++
34 | }
35 |
36 | fun replace(index: Int, value: String) {
37 | if (index > -1 && index < length)
38 | array[index] = value
39 | else
40 | println("IndexOutOfBounds")
41 | }
42 |
43 | fun pop() {
44 | if (length > 0) {
45 | length--
46 | }
47 | }
48 |
49 | fun delete(index: Int) {
50 | if (index > -1 && index < length) {
51 | if (index == length - 1) {
52 | pop()
53 | } else {
54 | for (i in index until length) {
55 | array[i] = array[i + 1]
56 | }
57 | length--
58 | }
59 | } else {
60 | println("IndexOutOfBounds")
61 | }
62 | }
63 |
64 | fun array(): Array {
65 | val tempArr = arrayOfNulls(length)
66 | for (i in 0 until length) {
67 | tempArr[i] = array[i]
68 | }
69 | return tempArr
70 | }
71 | }
72 | ```
--------------------------------------------------------------------------------
/src/data_structures/arrays/implementation/DynamicArray.kt:
--------------------------------------------------------------------------------
1 | package data_structures.arrays.implementation
2 |
3 | /**
4 | * Implementation of array data structure that can dynamically resize itself as needed.
5 | *
6 | * @constructor Creates an empty dynamic array.
7 | * @property array The array used to store elements.
8 | * @property capacity The current capacity of the array.
9 | * @property length The current number of elements in the array.
10 | */
11 | class DynamicArray(
12 | private var array: Array = arrayOfNulls(1),
13 | private var capacity: Int = 1,
14 | var length: Int = 0
15 | ) {
16 |
17 | /**
18 | * Returns the element at the specified index.
19 | *
20 | * @param index The index of the element to retrieve.
21 | * @return The element at the specified index, or "IndexOutOfBounds" if the index is out of range.
22 | */
23 | fun get(index: Int): String? {
24 | return if (index > -1 && index < length) array[index] else "IndexOutOfBounds"
25 | }
26 |
27 | /**
28 | * Appends the specified element to the end of the array.
29 | * If the array is full, its capacity is doubled before the element is added.
30 | *
31 | * @param string The element to add.
32 | */
33 | fun push(string: String) {
34 | if (length == capacity) {
35 | val tempArray = arrayOfNulls(2 * capacity)
36 | for (i in array.indices) {
37 | tempArray[i] = array[i]
38 | }
39 | array = tempArray
40 | capacity *= 2
41 | }
42 | array[length] = string
43 | length++
44 | }
45 |
46 | /**
47 | * Replaces the element at the specified index with the specified value.
48 | *
49 | * @param index The index of the element to replace.
50 | * @param value The new value to set.
51 | */
52 | fun replace(index: Int, value: String) {
53 | if (index > -1 && index < length)
54 | array[index] = value
55 | else
56 | println("IndexOutOfBounds")
57 | }
58 |
59 | /**
60 | * Removes the last element from the array.
61 | */
62 | fun pop() {
63 | if (length > 0) {
64 | length--
65 | }
66 | }
67 |
68 | /**
69 | * Removes the element at the specified index from the array.
70 | *
71 | * @param index The index of the element to remove.
72 | */
73 | fun delete(index: Int) {
74 | if (index > -1 && index < length) {
75 | if (index == length - 1) {
76 | pop()
77 | } else {
78 | for (i in index until length) {
79 | array[i] = array[i + 1]
80 | }
81 | length--
82 | }
83 | } else {
84 | println("IndexOutOfBounds")
85 | }
86 | }
87 |
88 | /**
89 | * Returns a new array containing all of the elements in this DynamicArray.
90 | *
91 | * @return An array containing all of the elements in this DynamicArray.
92 | */
93 | fun array(): Array {
94 | val tempArr = arrayOfNulls(length)
95 | for (i in 0 until length) {
96 | tempArr[i] = array[i]
97 | }
98 | return tempArr
99 | }
100 | }
101 |
102 | fun main() {
103 |
104 | val dynamicArray = DynamicArray()
105 | dynamicArray.push("apple")
106 | dynamicArray.push("ball")
107 | dynamicArray.push("cat")
108 | dynamicArray.push("dog")
109 |
110 | println("Array length: " + dynamicArray.length)
111 | println("array: " + dynamicArray.array().contentToString())
112 | println("item at index 2: " + dynamicArray.get(2))
113 |
114 | dynamicArray.replace(1, "world")
115 | println("array: " + dynamicArray.array().contentToString())
116 |
117 | dynamicArray.pop()
118 | println("array: " + dynamicArray.array().contentToString())
119 |
120 | dynamicArray.delete(1)
121 | println("array: " + dynamicArray.array().contentToString())
122 |
123 | println("Array length: " + dynamicArray.length)
124 | }
--------------------------------------------------------------------------------
/src/data_structures/arrays/merge_sorted_arrays/MergeSortedArrays.kt:
--------------------------------------------------------------------------------
1 | package data_structures.arrays.merge_sorted_arrays
2 |
3 | /**
4 | * This function takes two sorted arrays of integers as input and returns a single sorted array that contains all the elements of both input arrays.
5 | *
6 | * @param arr1 First sorted integer array
7 | * @param arr2 Second sorted integer array
8 | * @return Single sorted integer array that contains all the elements of both input arrays
9 | */
10 | fun mergeSortedArrays(arr1: IntArray, arr2: IntArray): IntArray {
11 | // Initialize indices for arr1, arr2, and the merged array
12 | var i = 0
13 | var j = 0
14 | var k = 0
15 | // Initialize a new array to hold the merged and sorted values
16 | val mergedArray = IntArray(arr1.size + arr2.size)
17 | // Compare values from arr1 and arr2 and insert them into the merged array in ascending order
18 | while (i < arr1.size && j < arr2.size) {
19 | if (arr1[i] < arr2[j]) {
20 | mergedArray[k] = arr1[i]
21 | i++
22 | } else {
23 | mergedArray[k] = arr2[j]
24 | j++
25 | }
26 | k++
27 | }
28 | // If arr1 has remaining values, append them to the merged array
29 | while (i < arr1.size) {
30 | mergedArray[k] = arr1[i]
31 | i++
32 | k++
33 | }
34 | // If arr2 has remaining values, append them to the merged array
35 | while (j < arr2.size) {
36 | mergedArray[k] = arr2[j]
37 | j++
38 | k++
39 | }
40 | // Return the merged and sorted array
41 | return mergedArray
42 | }
43 |
44 | fun main() {
45 |
46 | val mergedArray = mergeSortedArrays(intArrayOf(0, 2, 3, 56), intArrayOf(0, 6, 7))
47 | println(mergedArray.contentToString())
48 | }
--------------------------------------------------------------------------------
/src/data_structures/arrays/reverse_string/ReverseString.kt:
--------------------------------------------------------------------------------
1 | package data_structures.arrays.reverse_string
2 |
3 | /**
4 | * This function takes a String parameter and returns the reversed version of the input string.
5 | *
6 | * @param string String to reverse
7 | * @return Reversed input string
8 | */
9 | private fun reverse(string: String): String {
10 | // Initialize an empty string
11 | var result = ""
12 | // Iterate through the characters of the input string in reverse order
13 | for (i in string.length - 1 downTo 0) {
14 | // Append each character to the result string to form the reversed string
15 | result += string[i]
16 | }
17 | // Return the resulting reversed string
18 | return result
19 | }
20 |
21 | /**
22 | * This function uses Kotlin built-in function called reversed().
23 | *
24 | * @param string String to reverse
25 | * @return Reversed input string
26 | */
27 | private fun reverse2(string: String) = string.reversed()
28 |
29 | fun main() {
30 |
31 | println(reverse("Hello, World!"))
32 | println(reverse2("Hello, World!"))
33 | }
--------------------------------------------------------------------------------
/src/data_structures/graphs/Graph.kt:
--------------------------------------------------------------------------------
1 | package data_structures.graphs
2 |
3 | import java.util.*
4 | import kotlin.collections.ArrayList
5 |
6 | /**
7 | * A Kotlin class that represents an undirected graph using an adjacency list.
8 | *
9 | * @property numberOfNodes The number of nodes in the graph.
10 | * @property adjacentList The adjacency list that stores the connections between nodes.
11 | */
12 | class Graph(
13 | var numberOfNodes: Int = 0,
14 | var adjacentList: Hashtable> = Hashtable()
15 | ) {
16 |
17 | /**
18 | * Adds a new vertex (node) to the graph.
19 | * @param node The node to be added to the graph.
20 | */
21 | fun addVertex(node: Int) {
22 | adjacentList[node] = ArrayList()
23 | numberOfNodes++
24 | }
25 |
26 | /**
27 | * Adds an edge between two nodes in the graph.
28 | * @param node1 The first node of the edge.
29 | * @param node2 The second node of the edge.
30 | */
31 | fun addEdge(node1: Int, node2: Int) {
32 | adjacentList[node1]?.add(node2)
33 | adjacentList[node2]?.add(node1)
34 | }
35 |
36 | /**
37 | * Prints out the adjacency list that stores the connections between nodes in the graph.
38 | */
39 | fun showConnections() {
40 | val keys: Array = adjacentList.keys.toTypedArray()
41 | for (key in keys) {
42 | println(key.toString() + " --> " + adjacentList[key.toString().toInt()])
43 | }
44 | }
45 | }
46 |
47 | fun main() {
48 |
49 | val graph = Graph()
50 | graph.addVertex(5)
51 | graph.addVertex(54)
52 | graph.addVertex(44)
53 | graph.addEdge(5, 54)
54 | graph.addEdge(5, 44)
55 | graph.showConnections()
56 | }
--------------------------------------------------------------------------------
/src/data_structures/graphs/README.md:
--------------------------------------------------------------------------------
1 | ### Graphs
2 |
3 | Graph is a data structure that consists of a collection of nodes, also known as vertices, connected by edges. Graphs are
4 | a fundamental data structure used in many applications, such as social networks, web page ranking, transportation
5 | networks, and more. In a graph, nodes represent objects, and edges represent the relationships between them. Graphs can
6 | be either directed or undirected, depending on whether the edges have a direction or not. They can also be weighted or
7 | unweighted, depending on whether the edges have a value or not. Here's how we can implement a graph data structure:
8 |
9 | ```kotlin
10 | class Graph(
11 | var numberOfNodes: Int = 0,
12 | var adjacentList: Hashtable> = Hashtable()
13 | ) {
14 |
15 | fun addVertex(node: Int) {
16 | adjacentList[node] = ArrayList()
17 | numberOfNodes++
18 | }
19 |
20 | fun addEdge(node1: Int, node2: Int) {
21 | adjacentList[node1]?.add(node2)
22 | adjacentList[node2]?.add(node1)
23 | }
24 |
25 | fun showConnections() {
26 | val keys: Array = adjacentList.keys.toTypedArray()
27 | for (key in keys) {
28 | println(key.toString() + " --> " + adjacentList[key.toString().toInt()])
29 | }
30 | }
31 | }
32 | ```
--------------------------------------------------------------------------------
/src/data_structures/hash_tables/README.md:
--------------------------------------------------------------------------------
1 | ### Hash tables
2 |
3 | A hash table is a data structure that uses a hash function to map keys to unique indexes in an array, allowing for fast
4 | insertion, deletion, and retrieval of data. Each key is hashed to an index in the array where the corresponding value is
5 | stored. In case of collisions, where multiple keys map to the same index, the values are typically stored in a linked
6 | list or other data structure. Here's how we can implement a hash table data structure using `KeyValue` model:
7 |
8 | ```kotlin
9 | data class KeyValue(val key: String, val value: Int)
10 |
11 | class HashTable(size: Int) {
12 | private var data: Array?> = arrayOfNulls?>(size)
13 | private var currentLength: Int = 0
14 |
15 | private fun _hash(key: String): Int {
16 | var hash = 0
17 | for (i in key.indices) {
18 | hash = (hash + key.codePointAt(i) * i) % data.size
19 | }
20 | return hash
21 | }
22 |
23 | operator fun set(key: String, value: Int) {
24 | val address = _hash(key)
25 | if (data[address] == null) {
26 | val arrayAtAddress = ArrayList()
27 | data[address] = arrayAtAddress
28 | currentLength++
29 | }
30 | val pair = KeyValue(key, value)
31 | data[address]?.add(pair)
32 | }
33 |
34 | operator fun get(key: String): Int? {
35 | val address = _hash(key)
36 | val bucket = data[address]
37 | if (bucket != null) {
38 | for (keyValue in bucket) {
39 | if (keyValue.key == key) {
40 | return keyValue.value
41 | }
42 | }
43 | }
44 | return null
45 | }
46 |
47 | fun keys(): Array {
48 | val bucket = data
49 | val keysArray = arrayOfNulls(currentLength)
50 | var count = 0
51 | for (keyValues in bucket) {
52 | if (keyValues != null) {
53 | keysArray[count] = keyValues[0].key
54 | count++
55 | }
56 | }
57 | return keysArray
58 | }
59 | }
60 | ```
--------------------------------------------------------------------------------
/src/data_structures/hash_tables/first_recurring_character/FirstRecurring.kt:
--------------------------------------------------------------------------------
1 | package data_structures.hash_tables.first_recurring_character
2 |
3 | /**
4 | * Finds the first recurring integer in an array of integers.
5 | * @param array an integer array to search for recurring integer
6 | * @return The first recurring integer or null if none found
7 | */
8 | private fun firstRecurringCharacter(array: IntArray): Int? {
9 | val hashSet = HashSet()
10 | for (element in array) {
11 | if (hashSet.contains(element)) {
12 | return element
13 | } else {
14 | hashSet.add(element)
15 | }
16 | }
17 | return null
18 | }
19 |
20 | fun main() {
21 |
22 | val firstRecurring = firstRecurringCharacter(intArrayOf(2, 5, 5, 2, 3, 5, 1, 2, 4))
23 | println(firstRecurring)
24 | }
--------------------------------------------------------------------------------
/src/data_structures/hash_tables/implementation/HashTable.kt:
--------------------------------------------------------------------------------
1 | package data_structures.hash_tables.implementation
2 |
3 | import java.util.*
4 |
5 | /**
6 | * A class representing a hash table data structure that stores key-value pairs.
7 | * @param size the initial size of the hash table
8 | */
9 | class HashTable(size: Int) {
10 | private var data: Array?> = arrayOfNulls?>(size)
11 | private var currentLength: Int = 0
12 |
13 | /**
14 | * A private hash function that takes a key as input and returns its corresponding hash code.
15 | * @param key the key to hash
16 | * @return the hash code of the key
17 | */
18 | private fun _hash(key: String): Int {
19 | var hash = 0
20 | for (i in key.indices) {
21 | hash = (hash + key.codePointAt(i) * i) % data.size
22 | }
23 | return hash
24 | }
25 |
26 | /**
27 | * A method that inserts a key-value pair into the hash table.
28 | * @param key the key of the pair to insert
29 | * @param value the value of the pair to insert
30 | */
31 | operator fun set(key: String, value: Int) {
32 | val address = _hash(key)
33 | if (data[address] == null) {
34 | val arrayAtAddress = ArrayList()
35 | data[address] = arrayAtAddress
36 | currentLength++
37 | }
38 | val pair = KeyValue(key, value)
39 | data[address]?.add(pair)
40 | }
41 |
42 | /**
43 | * A method that retrieves the value associated with a given key from the hash table.
44 | * @param key the key of the pair to retrieve
45 | * @return the value associated with the given key or null if the key is not found
46 | */
47 | operator fun get(key: String): Int? {
48 | val address = _hash(key)
49 | val bucket = data[address]
50 | if (bucket != null) {
51 | for (keyValue in bucket) {
52 | if (keyValue.key == key) {
53 | return keyValue.value
54 | }
55 | }
56 | }
57 | return null
58 | }
59 |
60 | /**
61 | * A method that returns an array of all keys in the hash table.
62 | * @return an array of all keys in the hash table
63 | */
64 | fun keys(): Array {
65 | val bucket = data
66 | val keysArray = arrayOfNulls(currentLength)
67 | var count = 0
68 | for (keyValues in bucket) {
69 | if (keyValues != null) {
70 | keysArray[count] = keyValues[0].key
71 | count++
72 | }
73 | }
74 | return keysArray
75 | }
76 | }
77 |
78 | fun main() {
79 |
80 | val hashTable = HashTable(50)
81 | hashTable["grapes"] = 1200
82 | hashTable["apple"] = 1500
83 | println("value for key grapes: " + hashTable["grapes"])
84 | println("value for key apple: " + hashTable["apple"])
85 | println("list of keys: " + hashTable.keys().contentToString())
86 | }
--------------------------------------------------------------------------------
/src/data_structures/hash_tables/implementation/KeyValue.kt:
--------------------------------------------------------------------------------
1 | package data_structures.hash_tables.implementation
2 |
3 | /**
4 | * A data class representing a key-value pair.
5 | * @param key the key of the pair
6 | * @param value the value of the pair
7 | */
8 | data class KeyValue(val key: String, val value: Int)
--------------------------------------------------------------------------------
/src/data_structures/linked_lists/doubly_linked_list/DoublyLinkedList.kt:
--------------------------------------------------------------------------------
1 | package data_structures.linked_lists.doubly_linked_list
2 |
3 | /**
4 | * Implementation of a doubly linked list data structure with basic operations.
5 | */
6 | class DoublyLinkedList(value: Int) {
7 | var head: Node? = Node(value)
8 | var tail: Node? = head
9 | var length: Int = 1
10 |
11 | /**
12 | * Append a new node to the end of the list.
13 | *
14 | * @param value the value to be added to the list
15 | */
16 | fun append(value: Int) {
17 | val newNode = Node(value)
18 | newNode.previous = tail
19 | tail?.next = newNode
20 | tail = newNode
21 | length++
22 | }
23 |
24 | /**
25 | * Prepend a new node to the beginning of the list.
26 | *
27 | * @param value the value to be added to the list
28 | */
29 | fun prepend(value: Int) {
30 | val newNode = Node(value)
31 | head?.previous = newNode
32 | newNode.next = head
33 | head = newNode
34 | length++
35 | }
36 |
37 | /**
38 | * Print the values of the nodes in the list as an IntArray.
39 | *
40 | * @return an IntArray representing the values of the nodes in the list
41 | */
42 | fun printList(): IntArray {
43 | val myList = IntArray(length)
44 | var current: Node? = head
45 | var i = 0
46 | while (current != null) {
47 | myList[i] = current.value
48 | current = current.next
49 | i++
50 | }
51 | return myList
52 | }
53 |
54 | /**
55 | * Insert a new node at the specified index in the list.
56 | *
57 | * @param index the index at which to insert the new node
58 | * @param value the value to be inserted into the list
59 | */
60 | fun insert(index: Int, value: Int) {
61 | if (index < 0 || index > length) {
62 | println("Index Out Of Bounds For Length $length")
63 | } else if (index == 0) {
64 | prepend(value)
65 | } else if (index == length) {
66 | append(value)
67 | } else {
68 | var current: Node? = head
69 | for (i in 0 until index - 1) {
70 | current = current?.next
71 | }
72 | val newNode = Node(value)
73 | newNode.next = current?.next
74 | current?.next = newNode
75 | newNode.previous = current
76 | newNode.next?.previous = newNode
77 | length++
78 | }
79 | }
80 |
81 | /**
82 | * Remove the node at the specified index from the list.
83 | *
84 | * @param index the index of the node to be removed from the list
85 | */
86 | fun remove(index: Int) {
87 | if (index < 0 || index > length) {
88 | println("Index Out Of Bounds For Length $length")
89 | } else if (index == 0) {
90 | head = head?.next
91 | head?.previous = null
92 | length--
93 | } else {
94 | var current: Node? = head
95 | var i = 0
96 | while (i < index - 1) {
97 | current = current?.next
98 | i++
99 | }
100 | current?.next = current?.next?.next
101 | length--
102 | if (i == length - 1) {
103 | tail = current
104 | } else {
105 | current?.next?.previous = current
106 | }
107 | }
108 | }
109 | }
110 |
111 | fun main() {
112 |
113 | val myDoublyLinkedList = DoublyLinkedList(5)
114 |
115 | myDoublyLinkedList.append(3)
116 | myDoublyLinkedList.append(4)
117 | myDoublyLinkedList.prepend(2)
118 | myDoublyLinkedList.prepend(1)
119 | println(myDoublyLinkedList.printList().contentToString())
120 |
121 | myDoublyLinkedList.remove(0)
122 | println(myDoublyLinkedList.printList().contentToString())
123 |
124 | myDoublyLinkedList.insert(2, 200)
125 | println(myDoublyLinkedList.printList().contentToString())
126 |
127 | println("length: " + myDoublyLinkedList.length)
128 | println("head value: " + myDoublyLinkedList.head?.value)
129 | println("head.previous: " + myDoublyLinkedList.head?.previous)
130 | println("tail value: " + myDoublyLinkedList.tail?.value)
131 | println("tail.next: " + myDoublyLinkedList.tail?.next)
132 | }
--------------------------------------------------------------------------------
/src/data_structures/linked_lists/doubly_linked_list/Node.kt:
--------------------------------------------------------------------------------
1 | package data_structures.linked_lists.doubly_linked_list
2 |
3 | class Node(var value: Int) {
4 | var next: Node? = null
5 | var previous: Node? = null
6 | }
--------------------------------------------------------------------------------
/src/data_structures/linked_lists/singly_linked_list/Node.kt:
--------------------------------------------------------------------------------
1 | package data_structures.linked_lists.singly_linked_list
2 |
3 | class Node(var value: Int) {
4 | var next: Node? = null
5 | }
--------------------------------------------------------------------------------
/src/data_structures/linked_lists/singly_linked_list/SinglyLinkedList.kt:
--------------------------------------------------------------------------------
1 | package data_structures.linked_lists.singly_linked_list
2 |
3 | /**
4 | * Implementation of a singly linked list data structure with basic operations.
5 | */
6 | class LinkedList(value: Int) {
7 | private var head: Node? = Node(value)
8 | private var tail: Node? = head
9 | var length: Int = 1
10 |
11 | /**
12 | * Appends a new node with the given value to the end of the list.
13 | *
14 | * @param value the integer value to add to the list
15 | */
16 | fun append(value: Int) {
17 | val newNode = Node(value)
18 | tail?.next = newNode
19 | tail = newNode
20 | length++
21 | }
22 |
23 | /**
24 | * Adds a new node with the given value to the beginning of the list.
25 | *
26 | * @param value the integer value to add to the list
27 | */
28 | fun prepend(value: Int) {
29 | val newNode = Node(value)
30 | newNode.next = head
31 | head = newNode
32 | length++
33 | }
34 |
35 | /**
36 | * Returns an array containing the values of all nodes in the list.
37 | *
38 | * @return an array containing the values of all nodes in the list
39 | */
40 | fun printList(): IntArray {
41 | val myList = IntArray(length)
42 | var current: Node? = head
43 | var i = 0
44 | while (current != null) {
45 | myList[i] = current.value
46 | current = current.next
47 | i++
48 | }
49 | return myList
50 | }
51 |
52 | /**
53 | * Inserts a new node with the given value at the specified index.
54 | *
55 | * @param index the index at which to insert the new node
56 | * @param value the integer value to add to the list
57 | */
58 | fun insert(index: Int, value: Int) {
59 | if (index < 0 || index > length) {
60 | println("Index Out Of Bounds For Length $length")
61 | } else if (index == 0) {
62 | prepend(value)
63 | } else if (index == length) {
64 | append(value)
65 | } else {
66 | var current: Node? = head
67 | for (i in 0 until index - 1) {
68 | current = current?.next
69 | }
70 | val newNode = Node(value)
71 | newNode.next = current?.next
72 | current?.next = newNode
73 | length++
74 | }
75 | }
76 |
77 | /**
78 | * Removes the node at the specified index from the list.
79 | *
80 | * @param index the index of the node to remove
81 | */
82 | fun remove(index: Int) {
83 | if (index < 0 || index > length) {
84 | println("Index Out Of Bounds For Length $length")
85 | } else if (index == 0) {
86 | head = head?.next
87 | length--
88 | } else {
89 | var current: Node? = head
90 | var i = 0
91 | while (i < index - 1) {
92 | current = current?.next
93 | i++
94 | }
95 | current?.next = current?.next?.next
96 | length--
97 | if (i == length - 1) {
98 | tail = current
99 | }
100 | }
101 | }
102 |
103 | /**
104 | * Reverses the order of nodes in the list.
105 | *
106 | * @param linkedList the list to be reversed
107 | * @return a new reversed LinkedList
108 | */
109 | fun reverse(linkedList: LinkedList): LinkedList {
110 | val newList = LinkedList(linkedList.head!!.value)
111 | var current: Node? = linkedList.head
112 | while (current?.next != null) {
113 | current = current.next
114 | val newNode = Node(current!!.value)
115 | newNode.next = newList.head
116 | newList.head = newNode
117 | newList.length++
118 | }
119 | return newList
120 | }
121 | }
122 |
123 | fun main() {
124 |
125 | val myLinkedList = LinkedList(10)
126 |
127 | myLinkedList.append(12)
128 | myLinkedList.append(16)
129 |
130 | myLinkedList.prepend(20)
131 | myLinkedList.prepend(50)
132 | println("Length: " + myLinkedList.length)
133 | println("List: " + myLinkedList.printList().contentToString())
134 |
135 | myLinkedList.insert(2, 25)
136 | println("Length: " + myLinkedList.length)
137 | println("List: " + myLinkedList.printList().contentToString())
138 |
139 | myLinkedList.remove(4)
140 | println("Length: " + myLinkedList.length)
141 | println("List: " + myLinkedList.printList().contentToString())
142 |
143 | val linkedList2 = myLinkedList.reverse(myLinkedList)
144 | println("Reversed linked list: " + linkedList2.printList().contentToString())
145 | }
--------------------------------------------------------------------------------
/src/data_structures/queues/queue_using_linked_list/Node.kt:
--------------------------------------------------------------------------------
1 | package data_structures.queues.queue_using_linked_list
2 |
3 | /**
4 | * Represents a node in the linked-list used for the Queue.
5 | *
6 | * @param value The value to be stored in the node.
7 | * @param next The reference to the next node in the linked-list.
8 | */
9 | class Node(var value: String?, var next: Node? = null)
--------------------------------------------------------------------------------
/src/data_structures/queues/queue_using_linked_list/Queue.kt:
--------------------------------------------------------------------------------
1 | package data_structures.queues.queue_using_linked_list
2 |
3 | /**
4 | * Simple implementation of a queue data structure using linked list.
5 | *
6 | * @property first Points to the first node in the queue.
7 | * @property last Points to the last node in the queue.
8 | * @property length Represents the number of elements currently in the queue.
9 | */
10 | class Queue {
11 | var first: Node? = null
12 | var last: Node? = null
13 | var length = 0
14 |
15 | /**
16 | * Returns the value of the first element in the queue without removing it.
17 | *
18 | * @return The value of the first element if the queue is not empty, otherwise null.
19 | */
20 | fun peek(): String? {
21 | return if (length > 0) {
22 | first?.value
23 | } else {
24 | null
25 | }
26 | }
27 |
28 | /**
29 | * Adds an element with the given value to the end of the queue.
30 | *
31 | * @param value The value to be added to the queue.
32 | */
33 | fun enqueue(value: String?) {
34 | val newNode = Node(value)
35 | if (length == 0) {
36 | first = newNode
37 | } else {
38 | last?.next = newNode
39 | }
40 | last = newNode
41 | length++
42 | }
43 |
44 | /**
45 | * Removes the first element from the queue if it's not empty.
46 | */
47 | fun dequeue() {
48 | if (length > 0) {
49 | first = first?.next
50 | if (length == 1) {
51 | last = null
52 | }
53 | length--
54 | }
55 | }
56 |
57 | /**
58 | * Checks if the queue is empty.
59 | *
60 | * @return True if the queue is empty, otherwise false.
61 | */
62 | fun isEmpty() = length == 0
63 | }
64 |
65 | fun main() {
66 |
67 | val myQueue = Queue()
68 | println(myQueue.isEmpty())
69 | println(myQueue.peek())
70 | myQueue.enqueue("Apple")
71 | myQueue.enqueue("Ball")
72 | myQueue.enqueue("Cat")
73 | myQueue.dequeue()
74 | println(myQueue.peek())
75 | }
--------------------------------------------------------------------------------
/src/data_structures/queues/queue_using_stacks/Queue.kt:
--------------------------------------------------------------------------------
1 | package data_structures.queues.queue_using_stacks
2 |
3 | import java.util.*
4 |
5 | /**
6 | * Simple implementation of a queue data structure using stacks.
7 | *
8 | * @property queueStack The main stack used to simulate the queue.
9 | * @property revStack A temporary stack used for reordering elements during the push operation.
10 | */
11 | class Queue {
12 | var queueStack = Stack()
13 |
14 | private var revStack = Stack()
15 | /**
16 | * Adds an element with the value 'x' to the end of the queue.
17 | *
18 | * @param x The value to be added to the queue.
19 | */
20 | fun push(x: Int) {
21 | if (queueStack.size == 0) {
22 | queueStack.push(x)
23 | } else {
24 | while (queueStack.size != 0) {
25 | revStack.push(queueStack.pop())
26 | }
27 | revStack.push(x)
28 | while (revStack.size != 0) {
29 | queueStack.push(revStack.pop())
30 | }
31 | }
32 | }
33 |
34 | /**
35 | * Removes and returns the first element from the queue if it's not empty.
36 | *
37 | * @return The first element from the queue, or null if the queue is empty.
38 | */
39 | fun pop(): Int? {
40 | return if (queueStack.size > 0) {
41 | queueStack.pop()
42 | } else {
43 | null
44 | }
45 | }
46 |
47 | /**
48 | * Returns the value of the first element in the queue without removing it.
49 | *
50 | * @return The value of the first element if the queue is not empty, otherwise null.
51 | */
52 | fun peek(): Int? {
53 | return if (queueStack.size > 0) {
54 | queueStack[queueStack.size - 1]
55 | } else {
56 | null
57 | }
58 | }
59 |
60 | /**
61 | * Checks if the queue is empty.
62 | *
63 | * @return True if the queue is empty, otherwise false.
64 | */
65 | fun empty() = queueStack.size == 0
66 | }
67 |
68 | fun main() {
69 | val myQueue = Queue()
70 | myQueue.push(10)
71 | myQueue.push(20)
72 | myQueue.push(30)
73 | println("queue: " + myQueue.queueStack)
74 | println("peek: " + myQueue.peek())
75 | println("pop: " + myQueue.pop())
76 | println("queue: " + myQueue.queueStack)
77 | println("peek: " + myQueue.peek())
78 | println("is queue empty: " + myQueue.empty())
79 | }
--------------------------------------------------------------------------------
/src/data_structures/stacks/stack_using_array/Stack.kt:
--------------------------------------------------------------------------------
1 | package data_structures.stacks.stack_using_array
2 |
3 | import java.util.*
4 |
5 | /**
6 | * Simple implementation of a stack data structure using array.
7 | *
8 | * @property stackArray An ArrayList used to store the elements of the stack.
9 | */
10 | class Stack {
11 | private var stackArray: ArrayList = ArrayList()
12 |
13 | /**
14 | * Returns the value of the top element in the stack without removing it.
15 | *
16 | * @return The value of the top element if the stack is not empty, otherwise null.
17 | */
18 | fun peek(): String? {
19 | return if (stackArray.size > 0) {
20 | stackArray[stackArray.size - 1]
21 | } else {
22 | null
23 | }
24 | }
25 |
26 | /**
27 | * Adds an element with the given value to the top of the stack.
28 | *
29 | * @param value The value to be added to the stack.
30 | */
31 | fun push(value: String) {
32 | stackArray.add(value)
33 | }
34 |
35 | /**
36 | * Removes the top element from the stack if it's not empty.
37 | */
38 | fun pop() {
39 | if (stackArray.size > 0) {
40 | stackArray.removeAt(stackArray.size - 1)
41 | }
42 | }
43 |
44 | /**
45 | * Checks if the stack is empty.
46 | *
47 | * @return True if the stack is empty, otherwise false.
48 | */
49 | fun isEmpty() = stackArray.size == 0
50 | }
51 |
52 | fun main() {
53 |
54 | val myStack = Stack()
55 | myStack.push("Google")
56 | myStack.push("Udemy")
57 | myStack.push("Discord")
58 | println(myStack.peek())
59 | myStack.pop()
60 | println(myStack.peek())
61 | println(myStack.isEmpty())
62 | }
--------------------------------------------------------------------------------
/src/data_structures/stacks/stack_using_linked_list/Node.kt:
--------------------------------------------------------------------------------
1 | package data_structures.stacks.stack_using_linked_list
2 |
3 | /**
4 | * Represents a node in the linked-list used for the Stack.
5 | *
6 | * @param value The value to be stored in the node.
7 | * @param next The reference to the next node in the linked-list.
8 | */
9 | class Node(val value: String?, var next: Node? = null)
--------------------------------------------------------------------------------
/src/data_structures/stacks/stack_using_linked_list/Stack.kt:
--------------------------------------------------------------------------------
1 | package data_structures.stacks.stack_using_linked_list
2 |
3 | /**
4 | * Simple implementation of a stack data structure using linked list.
5 | *
6 | * @property top Points to the top node in the stack.
7 | * @property bottom Points to the bottom node in the stack.
8 | * @property length Represents the number of elements currently in the stack.
9 | */
10 | class Stack {
11 | private var top: Node? = null
12 | private var bottom: Node? = null
13 | private var length = 0
14 |
15 | /**
16 | * Returns the value of the top element in the stack without removing it.
17 | *
18 | * @return The value of the top element if the stack is not empty, otherwise null.
19 | */
20 | fun peek(): String? {
21 | return if (length > 0) {
22 | top?.value
23 | } else {
24 | null
25 | }
26 | }
27 |
28 | /**
29 | * Adds an element with the given value to the top of the stack.
30 | *
31 | * @param value The value to be added to the stack.
32 | */
33 | fun push(value: String?) {
34 | val newNode = Node(value)
35 | if (length == 0) {
36 | top = newNode
37 | bottom = newNode
38 | } else {
39 | newNode.next = top
40 | top = newNode
41 | }
42 | length++
43 | }
44 |
45 | /**
46 | * Removes the top element from the stack if it's not empty.
47 | */
48 | fun pop() {
49 | if (length > 0) {
50 | top = top?.next
51 | if (length == 1) {
52 | bottom = null
53 | }
54 | length--
55 | }
56 | }
57 |
58 | /**
59 | * Checks if the stack is empty.
60 | *
61 | * @return True if the stack is empty, otherwise false.
62 | */
63 | fun isEmpty() = length == 0
64 |
65 | /**
66 | * Returns the value of the last element in the stack without removing it.
67 | *
68 | * @return The value of the last element if the stack is not empty, otherwise null.
69 | */
70 | val lastElement: String?
71 | get() = if (length > 0) {
72 | bottom?.value
73 | } else null
74 | }
75 |
76 | fun main() {
77 |
78 | val myStack = Stack()
79 | myStack.push("Google")
80 | myStack.push("Udemy")
81 | myStack.push("Discord")
82 | println(myStack.peek())
83 | myStack.pop()
84 | println(myStack.isEmpty())
85 | println(myStack.lastElement)
86 | }
--------------------------------------------------------------------------------
/src/data_structures/trees/binary_search_tree/BinarySearchTree.kt:
--------------------------------------------------------------------------------
1 | package data_structures.trees.binary_search_tree
2 |
3 | import java.util.*
4 |
5 | /**
6 | * Simple implementation of a Binary Search Tree (BST) data structure.
7 | *
8 | * @property root Points to the root node of the binary search tree.
9 | */
10 | class BinarySearchTree {
11 | var root: Node? = null
12 |
13 | /**
14 | * Inserts a new node with the given value into the binary search tree.
15 | *
16 | * @param value The value to be inserted into the binary search tree.
17 | */
18 | fun insert(value: Int) {
19 | val newNode = Node(value)
20 | if (this.root == null) {
21 | // If the tree is empty, set the new node as the root.
22 | this.root = newNode
23 | } else {
24 | var current = this.root
25 | while (true) {
26 | // Traverse to the right subtree if the current node value is less than the new value.
27 | if (current!!.value < value) {
28 | if (current.right != null) {
29 | current = current.right
30 | } else {
31 | current.right = newNode
32 | break
33 | }
34 | } else {
35 | // Traverse to the left subtree if the current node value is greater than or equal to the new value.
36 | if (current.left != null) {
37 | current = current.left
38 | } else {
39 | current.left = newNode
40 | break
41 | }
42 | }
43 | }
44 | }
45 | }
46 |
47 | /**
48 | * Searches for a node with the given value in the binary search tree and returns true if found, otherwise false.
49 | *
50 | * @param value The value to be searched in the binary search tree.
51 | * @return True if the value is found, otherwise false.
52 | */
53 | fun lookup(value: Int): Boolean {
54 | var current = this.root
55 | while (current != null) {
56 | current = when {
57 | current.value > value -> {
58 | current.left
59 | }
60 | current.value < value -> {
61 | current.right
62 | }
63 | else -> {
64 | return true
65 | }
66 | }
67 | }
68 | return false
69 | }
70 |
71 | /**
72 | * Removes a node with the given value from the binary search tree.
73 | *
74 | * @param value The value of the node to be removed.
75 | */
76 | fun remove(value: Int) {
77 | if (this.root == null) {
78 | return
79 | }
80 | var current = this.root
81 | var parentNode: Node? = null
82 |
83 | // Traverse the tree to find the node to be removed.
84 | while (current != null) {
85 | when {
86 | value < current.value -> {
87 | // Go left if the value is smaller.
88 | parentNode = current
89 | current = current.left
90 | }
91 | value > current.value -> {
92 | // Go right if the value is greater.
93 | parentNode = current
94 | current = current.right
95 | }
96 | else -> {
97 | // Node to be removed is found.
98 |
99 | // Option 1: No right child.
100 | if (current.right == null) {
101 | // If parentNode is null, the root node is to be removed.
102 | if (parentNode == null) {
103 | this.root = current.left
104 | } else {
105 | // Make the left child of the current node a child of its parent.
106 | if (current.value < parentNode.value) {
107 | parentNode.left = current.left
108 | } else if (current.value > parentNode.value) {
109 | parentNode.right = current.left
110 | }
111 | }
112 | } else if (current.right!!.left == null) {
113 | // Option 2: Right child has no left child.
114 | if (parentNode == null) {
115 | this.root = current.right
116 | } else {
117 | // Make the right child of the current node a child of its parent.
118 | if (current.value < parentNode.value) {
119 | parentNode.left = current.right
120 | } else if (current.value > parentNode.value) {
121 | parentNode.right = current.right
122 | }
123 | }
124 | } else {
125 | // Option 3: Right child has left child.
126 | if (parentNode == null) {
127 | // Save references to the left and right nodes of the root.
128 | val leftNode = this.root!!.left
129 | val rightNode = this.root!!.right
130 |
131 | // Make the leftmost node of the right subtree the new root.
132 | this.root = current.right!!.left
133 |
134 | // Set the saved references of left and right nodes of the root.
135 | rightNode!!.left = rightNode.left!!.right
136 | this.root!!.left = leftNode
137 | this.root!!.right = rightNode
138 | } else {
139 | // Make the leftmost node of the right subtree a child of its parent.
140 | if (current.value < parentNode.value) {
141 | parentNode.left = current.right!!.left
142 | } else if (current.value > parentNode.value) {
143 | parentNode.right = current.right!!.left
144 | }
145 | }
146 | }
147 | return
148 | }
149 | }
150 | }
151 | }
152 |
153 | /**
154 | * Performs breadth-first search on the binary search tree and returns the values of the nodes in an ArrayList.
155 | *
156 | * @return An ArrayList containing the values of the nodes in breadth-first order.
157 | */
158 | fun breadthFirstSearch(): ArrayList {
159 | var currentNode = this.root
160 | val resultArray = ArrayList()
161 | val queue = ArrayList()
162 | queue.add(currentNode)
163 |
164 | // Traverse the tree in breadth-first order using a queue.
165 | while (queue.size > 0) {
166 | currentNode = queue.removeAt(0)
167 | resultArray.add(currentNode!!.value)
168 | if (currentNode.left != null) {
169 | queue.add(currentNode.left)
170 | }
171 | if (currentNode.right != null) {
172 | queue.add(currentNode.right)
173 | }
174 | }
175 | return resultArray
176 | }
177 |
178 | /**
179 | * Helper function for recursive breadth-first search.
180 | *
181 | * @param queue The queue used for recursive breadth-first search.
182 | * @param resultArray The ArrayList to store the values of the nodes in breadth-first order.
183 | * @return An ArrayList containing the values of the nodes in breadth-first order.
184 | */
185 | fun breadthFirstSearchRecursive(
186 | queue: ArrayList,
187 | resultArray: ArrayList
188 | ): ArrayList {
189 | // Base case: If the queue is empty, return the resultArray.
190 | if (queue.size == 0) {
191 | return resultArray
192 | }
193 |
194 | // Remove the first node from the queue and process it.
195 | val currentNode = queue.removeAt(0)
196 | resultArray.add(currentNode!!.value)
197 |
198 | // Add the left and right children of the current node to the queue if they exist.
199 | if (currentNode.left != null) {
200 | queue.add(currentNode.left)
201 | }
202 | if (currentNode.right != null) {
203 | queue.add(currentNode.right)
204 | }
205 |
206 | // Continue the recursive call with the updated queue and resultArray.
207 | return breadthFirstSearchRecursive(queue, resultArray)
208 | }
209 |
210 | /**
211 | * Performs depth-first search (in-order) on the binary search tree and returns the values of the nodes in an ArrayList.
212 | *
213 | * @return An ArrayList containing the values of the nodes in in-order depth-first search order.
214 | */
215 | fun DFSInOrder(): ArrayList {
216 | val answer = ArrayList()
217 | return traverseInOrder(this.root, answer)
218 | }
219 |
220 | /**
221 | * Performs depth-first search (pre-order) on the binary search tree and returns the values of the nodes in an ArrayList.
222 | *
223 | * @return An ArrayList containing the values of the nodes in pre-order depth-first search order.
224 | */
225 | fun DFSPreOrder(): ArrayList {
226 | val answer = ArrayList()
227 | return traversePreOrder(this.root, answer)
228 | }
229 |
230 | /**
231 | * Performs depth-first search (post-order) on the binary search tree and returns the values of the nodes in an ArrayList.
232 | *
233 | * @return An ArrayList containing the values of the nodes in post-order depth-first search order.
234 | */
235 | fun DFSPostOrder(): ArrayList {
236 | val answer = ArrayList()
237 | return traversePostOrder(this.root, answer)
238 | }
239 |
240 | /**
241 | * Helper function for in-order traversal during depth-first search.
242 | *
243 | * @param node The current node being processed.
244 | * @param array The ArrayList to store the values of the nodes during in-order traversal.
245 | * @return An ArrayList containing the values of the nodes in in-order depth-first search order.
246 | */
247 | private fun traverseInOrder(node: Node?, array: ArrayList): ArrayList {
248 | if (node?.left != null) {
249 | traverseInOrder(node.left, array)
250 | }
251 | array.add(node?.value)
252 | if (node?.right != null) {
253 | traverseInOrder(node.right, array)
254 | }
255 | return array
256 | }
257 |
258 | /**
259 | * Helper function for pre-order traversal during depth-first search.
260 | *
261 | * @param node The current node being processed.
262 | * @param array The ArrayList to store the values of the nodes during pre-order traversal.
263 | * @return An ArrayList containing the values of the nodes in pre-order depth-first search order.
264 | */
265 | private fun traversePreOrder(node: Node?, array: ArrayList): ArrayList {
266 | array.add(node?.value)
267 | if (node?.left != null) {
268 | traversePreOrder(node.left, array)
269 | }
270 | if (node?.right != null) {
271 | traversePreOrder(node.right, array)
272 | }
273 | return array
274 | }
275 |
276 | /**
277 | * Helper function for post-order traversal during depth-first search.
278 | *
279 | * @param node The current node being processed.
280 | * @param array The ArrayList to store the values of the nodes during post-order traversal.
281 | * @return An ArrayList containing the values of the nodes in post-order depth-first search order.
282 | */
283 | private fun traversePostOrder(node: Node?, array: ArrayList): ArrayList {
284 | if (node?.left != null) {
285 | traversePostOrder(node.left, array)
286 | }
287 | if (node?.right != null) {
288 | traversePostOrder(node.right, array)
289 | }
290 | array.add(node?.value)
291 | return array
292 | }
293 | }
294 |
295 | fun main() {
296 | val bst = BinarySearchTree()
297 | bst.insert(9)
298 | bst.insert(4)
299 | bst.insert(6)
300 | bst.insert(20)
301 | bst.insert(170)
302 | bst.insert(15)
303 | bst.insert(1)
304 | println("bfs: " + bst.breadthFirstSearch())
305 | println("look for 20: " + bst.lookup(20))
306 | val queue = ArrayList()
307 | queue.add(bst.root)
308 | println("bfs recursive: " + bst.breadthFirstSearchRecursive(queue, ArrayList()))
309 | println("dfs inOrder: " + bst.DFSInOrder())
310 | println("dfs preOrder: " + bst.DFSPreOrder())
311 | println("dfs postOrder: " + bst.DFSPostOrder())
312 | bst.remove(20)
313 | println("look for 20 after removing 20: " + bst.lookup(20))
314 | }
--------------------------------------------------------------------------------
/src/data_structures/trees/binary_search_tree/BinarySearchTreeNoComments.kt:
--------------------------------------------------------------------------------
1 | package data_structures.trees.binary_search_tree
2 |
3 | import java.util.ArrayList
4 |
5 | class BinarySearchTreeNoComments {
6 | var root: Node? = null
7 |
8 | fun insert(value: Int) {
9 | val newNode = Node(value)
10 | if (this.root == null) {
11 | this.root = newNode
12 | } else {
13 | var current = this.root
14 | while (true) {
15 | if (current!!.value < value) {
16 | if (current.right != null) {
17 | current = current.right
18 | } else {
19 | current.right = newNode
20 | break
21 | }
22 | } else {
23 | if (current.left != null) {
24 | current = current.left
25 | } else {
26 | current.left = newNode
27 | break
28 | }
29 | }
30 | }
31 | }
32 | }
33 |
34 | fun lookup(value: Int): Boolean {
35 | var current = this.root
36 | while (current != null) {
37 | current = when {
38 | current.value > value -> {
39 | current.left
40 | }
41 | current.value < value -> {
42 | current.right
43 | }
44 | else -> {
45 | return true
46 | }
47 | }
48 | }
49 | return false
50 | }
51 |
52 | fun remove(value: Int) {
53 | if (this.root == null) {
54 | return
55 | }
56 | var current = this.root
57 | var parentNode: Node? = null
58 |
59 | while (current != null) {
60 | when {
61 | value < current.value -> {
62 | parentNode = current
63 | current = current.left
64 | }
65 | value > current.value -> {
66 | parentNode = current
67 | current = current.right
68 | }
69 | else -> {
70 | if (current.right == null) {
71 | if (parentNode == null) {
72 | this.root = current.left
73 | } else {
74 | if (current.value < parentNode.value) {
75 | parentNode.left = current.left
76 | } else if (current.value > parentNode.value) {
77 | parentNode.right = current.left
78 | }
79 | }
80 | } else if (current.right!!.left == null) {
81 | if (parentNode == null) {
82 | this.root = current.right
83 | } else {
84 | if (current.value < parentNode.value) {
85 | parentNode.left = current.right
86 | } else if (current.value > parentNode.value) {
87 | parentNode.right = current.right
88 | }
89 | }
90 | } else {
91 | if (parentNode == null) {
92 | val leftNode = this.root!!.left
93 | val rightNode = this.root!!.right
94 |
95 | this.root = current.right!!.left
96 |
97 | rightNode!!.left = rightNode.left!!.right
98 | this.root!!.left = leftNode
99 | this.root!!.right = rightNode
100 | } else {
101 | if (current.value < parentNode.value) {
102 | parentNode.left = current.right!!.left
103 | } else if (current.value > parentNode.value) {
104 | parentNode.right = current.right!!.left
105 | }
106 | }
107 | }
108 | return
109 | }
110 | }
111 | }
112 | }
113 |
114 | fun breadthFirstSearch(): ArrayList {
115 | var currentNode = this.root
116 | val resultArray = ArrayList()
117 | val queue = ArrayList()
118 | queue.add(currentNode)
119 |
120 | while (queue.size > 0) {
121 | currentNode = queue.removeAt(0)
122 | resultArray.add(currentNode!!.value)
123 | if (currentNode.left != null) {
124 | queue.add(currentNode.left)
125 | }
126 | if (currentNode.right != null) {
127 | queue.add(currentNode.right)
128 | }
129 | }
130 | return resultArray
131 | }
132 |
133 | fun breadthFirstSearchRecursive(
134 | queue: ArrayList,
135 | resultArray: ArrayList
136 | ): ArrayList {
137 | if (queue.size == 0) {
138 | return resultArray
139 | }
140 |
141 | val currentNode = queue.removeAt(0)
142 | resultArray.add(currentNode!!.value)
143 |
144 | if (currentNode.left != null) {
145 | queue.add(currentNode.left)
146 | }
147 | if (currentNode.right != null) {
148 | queue.add(currentNode.right)
149 | }
150 |
151 | return breadthFirstSearchRecursive(queue, resultArray)
152 | }
153 |
154 | fun DFSInOrder(): ArrayList {
155 | val answer = ArrayList()
156 | return traverseInOrder(this.root, answer)
157 | }
158 |
159 | fun DFSPreOrder(): ArrayList {
160 | val answer = ArrayList()
161 | return traversePreOrder(this.root, answer)
162 | }
163 |
164 | fun DFSPostOrder(): ArrayList {
165 | val answer = ArrayList()
166 | return traversePostOrder(this.root, answer)
167 | }
168 |
169 | private fun traverseInOrder(node: Node?, array: ArrayList): ArrayList {
170 | if (node?.left != null) {
171 | traverseInOrder(node.left, array)
172 | }
173 | array.add(node?.value)
174 | if (node?.right != null) {
175 | traverseInOrder(node.right, array)
176 | }
177 | return array
178 | }
179 |
180 | private fun traversePreOrder(node: Node?, array: ArrayList): ArrayList {
181 | array.add(node?.value)
182 | if (node?.left != null) {
183 | traversePreOrder(node.left, array)
184 | }
185 | if (node?.right != null) {
186 | traversePreOrder(node.right, array)
187 | }
188 | return array
189 | }
190 |
191 | private fun traversePostOrder(node: Node?, array: ArrayList): ArrayList {
192 | if (node?.left != null) {
193 | traversePostOrder(node.left, array)
194 | }
195 | if (node?.right != null) {
196 | traversePostOrder(node.right, array)
197 | }
198 | array.add(node?.value)
199 | return array
200 | }
201 | }
202 |
203 | fun main() {
204 | val bst = BinarySearchTreeNoComments()
205 | bst.insert(9)
206 | bst.insert(4)
207 | bst.insert(6)
208 | bst.insert(20)
209 | bst.insert(170)
210 | bst.insert(15)
211 | bst.insert(1)
212 | println("bfs: " + bst.breadthFirstSearch())
213 | println("look for 20: " + bst.lookup(20))
214 | val queue = ArrayList()
215 | queue.add(bst.root)
216 | println("bfs recursive: " + bst.breadthFirstSearchRecursive(queue, ArrayList()))
217 | println("dfs inOrder: " + bst.DFSInOrder())
218 | println("dfs preOrder: " + bst.DFSPreOrder())
219 | println("dfs postOrder: " + bst.DFSPostOrder())
220 | bst.remove(20)
221 | println("look for 20 after removing 20: " + bst.lookup(20))
222 | }
--------------------------------------------------------------------------------
/src/data_structures/trees/binary_search_tree/Node.kt:
--------------------------------------------------------------------------------
1 | package data_structures.trees.binary_search_tree
2 |
3 | /**
4 | * Represents a node in the binary search tree.
5 | *
6 | * @param value The value to be stored in the node.
7 | * @param left The reference to the left child node.
8 | * @param right The reference to the right child node.
9 | */
10 | class Node(val value: Int, var left: Node? = null, var right: Node? = null)
--------------------------------------------------------------------------------
/src/data_structures/trees/priority_queue/Node.kt:
--------------------------------------------------------------------------------
1 | package data_structures.trees.priority_queue
2 |
3 | /**
4 | * Represents a node in the priority queue.
5 | *
6 | * @param value The value to be stored in the node.
7 | * @param priority The priority of the node.
8 | */
9 | class Node(val value: String, val priority: Int)
--------------------------------------------------------------------------------
/src/data_structures/trees/priority_queue/PriorityQueue.kt:
--------------------------------------------------------------------------------
1 | package data_structures.trees.priority_queue
2 |
3 | /**
4 | * Simple implementation of a priority queue data structure.
5 | *
6 | * @property queueArray ArrayList that holds the nodes in the priority queue.
7 | */
8 | class PriorityQueue {
9 | private val queueArray = ArrayList()
10 |
11 | /**
12 | * Adds a new node with the given value and priority to the priority queue.
13 | *
14 | * @param value The value to be added to the priority queue.
15 | * @param priority The priority of the value. Higher values represent higher priority.
16 | */
17 | fun enqueue(value: String?, priority: Int) {
18 | val newNode = Node(value!!, priority)
19 | var contain = false
20 | for (i in queueArray.indices) {
21 | if (queueArray[i].priority > newNode.priority) {
22 | queueArray.add(i, newNode)
23 | contain = true
24 | break
25 | }
26 | }
27 | if (!contain) {
28 | queueArray.add(newNode)
29 | }
30 | }
31 |
32 | /**
33 | * Removes and returns the value of the node with the highest priority from the priority queue.
34 | *
35 | * @return The value of the node with the highest priority, or "empty array" if the queue is empty.
36 | */
37 | fun dequeue(): String {
38 | if (queueArray.isEmpty()) {
39 | return "empty array"
40 | }
41 | val toRemove = queueArray[0]
42 | queueArray.removeAt(0)
43 | return toRemove.value
44 | }
45 |
46 | /**
47 | * Returns the node with the highest priority in the priority queue without removing it.
48 | *
49 | * @return The node with the highest priority, or null if the queue is empty.
50 | */
51 | fun front(): Node? {
52 | return if (queueArray.isNotEmpty()) {
53 | queueArray[0]
54 | } else null
55 | }
56 |
57 | /**
58 | * Returns the node with the lowest priority in the priority queue without removing it.
59 | *
60 | * @return The node with the lowest priority, or null if the queue is empty.
61 | */
62 | fun rear(): Node? {
63 | return if (queueArray.isNotEmpty()) {
64 | queueArray[queueArray.size - 1]
65 | } else null
66 | }
67 |
68 | /**
69 | * Property that indicates whether the priority queue is empty or not.
70 | */
71 | val isEmpty: Boolean
72 | get() = queueArray.isEmpty()
73 |
74 | /**
75 | * Returns an array containing the values of all nodes in the priority queue.
76 | *
77 | * @return An array of String? containing the values of all nodes in the priority queue.
78 | */
79 | fun printQueue(): Array {
80 | val array = arrayOfNulls(queueArray.size)
81 | for (i in array.indices) {
82 | array[i] = queueArray[i].value
83 | }
84 | return array
85 | }
86 | }
87 |
88 | fun main() {
89 |
90 | val queue = PriorityQueue()
91 | queue.enqueue("piyush", 3)
92 | queue.enqueue("rohan", 1)
93 | queue.enqueue("jeet", 2)
94 | queue.enqueue("john", 5)
95 | queue.enqueue("Dave", 4)
96 | println(queue.printQueue().contentToString())
97 | println(queue.dequeue())
98 | println(queue.printQueue().contentToString())
99 | println(queue.front()?.value)
100 | println(queue.rear()?.value)
101 | println(queue.isEmpty)
102 | }
--------------------------------------------------------------------------------
/src/data_structures/trees/trie/Node.kt:
--------------------------------------------------------------------------------
1 | package data_structures.trees.trie
2 |
3 | import java.util.*
4 |
5 | /**
6 | * Represents a node in the trie.
7 | *
8 | * @param children Children of the current node.
9 | * @param isWord Indicates if the node represents the end of a complete word.
10 | */
11 | class Node(var children: HashMap = HashMap(), var isWord: Boolean = false)
--------------------------------------------------------------------------------
/src/data_structures/trees/trie/Trie.kt:
--------------------------------------------------------------------------------
1 | package data_structures.trees.trie
2 |
3 | /**
4 | * Simple implementation of a trie queue data structure.
5 | *
6 | * @property root The root node of the trie.
7 | */
8 | class Trie {
9 | val root = Node()
10 |
11 | /**
12 | * Inserts a string into the trie.
13 | *
14 | * @param string The string to be inserted into the trie.
15 | */
16 | fun insert(string: String) {
17 | var current: Node? = root
18 | for (ch in string.toCharArray()) {
19 | current!!.children.putIfAbsent(ch, Node())
20 | current = current.children[ch]
21 | }
22 | current!!.isWord = true
23 | }
24 |
25 | /**
26 | * Searches for a complete word in the trie and returns true if found, otherwise false.
27 | *
28 | * @param string The word to be searched in the trie.
29 | * @return True if the complete word is found, otherwise false.
30 | */
31 | fun findWord(string: String): Boolean {
32 | var current: Node? = root
33 | for (ch in string.toCharArray()) {
34 | current = if (current!!.children.containsKey(ch)) {
35 | current.children[ch]
36 | } else {
37 | return false
38 | }
39 | }
40 | return current!!.isWord
41 | }
42 |
43 | /**
44 | * Deletes a word from the trie and returns true if the word was successfully deleted, otherwise false.
45 | *
46 | * @param word The word to be deleted from the trie.
47 | * @return True if the word was successfully deleted, otherwise false.
48 | */
49 | fun delete(word: String): Boolean {
50 | var current: Node? = root
51 | var deleteAfter: Node? = root
52 | var ch1 = word[0]
53 | for (i in word.indices) {
54 | val ch = word[i]
55 | if (current!!.children.containsKey(ch)) {
56 | current = current.children[ch]
57 | if (current!!.children.size > 1) {
58 | deleteAfter = current
59 | ch1 = word[i + 1]
60 | }
61 | } else {
62 | return false
63 | }
64 | }
65 | if (current!!.children.isEmpty()) {
66 | deleteAfter!!.children.remove(ch1)
67 | return true
68 | }
69 | return false
70 | }
71 | }
72 |
73 | fun main() {
74 | val trie = Trie()
75 | trie.insert("heating")
76 | trie.insert("heat")
77 | println(trie.root.children['h']!!.children['e']?.children)
78 | println(trie.delete("heat"))
79 | println(trie.findWord("heat"))
80 | println(trie.root.children['h']!!.children['e']?.children)
81 | }
--------------------------------------------------------------------------------
/src/dynamic_programming/README.md:
--------------------------------------------------------------------------------
1 | ### Dynamic programming overview
2 |
3 | - Dynamic fibonacci
4 | - Dynamic fibonacci (sample)
5 | - Memoization
6 | - Memoization (sample)
7 |
8 | ### Dynamic programming definition
9 |
10 | Dynamic programming is a technique for solving complex problems by breaking them down into smaller, simpler subproblems and storing the solutions to those subproblems in a table. By solving these subproblems once and reusing their solutions, dynamic programming can dramatically reduce the amount of computation required to solve the original problem.
--------------------------------------------------------------------------------
/src/dynamic_programming/dynamic_fibonacci/DynamicFibonacci.kt:
--------------------------------------------------------------------------------
1 | package dynamic_programming.dynamic_fibonacci
2 |
3 | import dynamic_programming.dynamic_fibonacci.DynamicFibonacci.Companion.operationsCount
4 | import java.util.*
5 |
6 |
7 | /**
8 | * A class to calculate Fibonacci numbers using dynamic programming with memoization.
9 | */
10 | class DynamicFibonacci {
11 |
12 | /**
13 | * Calculates the nth Fibonacci number using memoization to avoid redundant calculations.
14 | *
15 | * @param n The index of the Fibonacci number to calculate.
16 | * @return The nth Fibonacci number.
17 | */
18 | fun fibonacciMaster(n: Int): Int {
19 | // Check if the value for 'n' is already available in the cache.
20 | return if (cache.containsKey(n)) {
21 | // If it's in the cache, return the cached value.
22 | cache[n]!!
23 | } else {
24 | // If not in the cache, calculate the Fibonacci number and add it to the cache.
25 | if (n < 2) {
26 | n
27 | } else {
28 | operationsCount++
29 | cache[n] = fibonacciMaster(n - 1) + fibonacciMaster(n - 2)
30 | cache[n]!!
31 | }
32 | }
33 | }
34 |
35 | companion object {
36 | // HashMap to store calculated Fibonacci numbers (memoization cache).
37 | var cache = HashMap()
38 | // Counter to keep track of the number of recursive calls made during calculations.
39 | var operationsCount = 0
40 | }
41 | }
42 |
43 | fun main() {
44 |
45 | val fib = DynamicFibonacci()
46 | println(fib.fibonacciMaster(30))
47 | println(operationsCount)
48 | }
--------------------------------------------------------------------------------
/src/dynamic_programming/memoization/Memoization.kt:
--------------------------------------------------------------------------------
1 | package dynamic_programming.memoization
2 |
3 | import java.util.*
4 |
5 | /**
6 | * A class demonstrating the concept of memoization in Kotlin.
7 | */
8 | class Memoization {
9 |
10 | /**
11 | * Calculates the sum of the given integer 'n' and 80 directly without memoization.
12 | *
13 | * @param n The integer to add to 80.
14 | * @return The sum of 'n' and 80.
15 | */
16 | fun addTo80(n: Int): Int {
17 | println("long time")
18 | return n + 80
19 | }
20 |
21 | /**
22 | * Calculates the sum of the given integer 'n' and 80 using memoization to avoid redundant calculations.
23 | *
24 | * @param n The integer to add to 80.
25 | * @return The sum of 'n' and 80, retrieved from the cache if previously calculated.
26 | */
27 | fun memoizeAddTo80(n: Int): Int {
28 | if (!cache.containsKey(n)) {
29 | println("long time")
30 | cache[n] = n + 80
31 | }
32 | return cache[n]!!
33 | }
34 |
35 | companion object {
36 | // HashMap to store previously calculated results for memoization (cache).
37 | var cache = HashMap()
38 | }
39 | }
40 |
41 | fun main() {
42 |
43 | val memo = Memoization()
44 | println("addTo80: " + memo.addTo80(5))
45 | println("addTo80: " + memo.addTo80(5))
46 | println("memoizeAddTo80: " + memo.memoizeAddTo80(5))
47 | println("memoizeAddTo80: " + memo.memoizeAddTo80(5))
48 | println("memoizeAddTo80: " + memo.memoizeAddTo80(5))
49 | }
--------------------------------------------------------------------------------