Repository: KiberneticWorm/Kotlin-Algorithms-and-Design-Patterns
Branch: develop
Commit: 1f89f062a056
Files: 140
Total size: 250.1 KB
Directory structure:
gitextract_pko15ir1/
├── .gitignore
├── LICENSE.txt
├── README.md
├── README_ru.md
├── build.gradle.kts
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── settings.gradle.kts
└── src/
├── main/
│ └── kotlin/
│ ├── design_patterns/
│ │ ├── Abstract Factory.kt
│ │ ├── Adapter.kt
│ │ ├── Bridge.kt
│ │ ├── Builder.kt
│ │ ├── Command.kt
│ │ ├── Composite.kt
│ │ ├── Decorator.kt
│ │ ├── Facade.kt
│ │ ├── Factory Method.kt
│ │ ├── Flyweight.kt
│ │ ├── Interpreter.kt
│ │ ├── Iterator.kt
│ │ ├── Mediator.kt
│ │ ├── Memento.kt
│ │ ├── Observer.kt
│ │ ├── Prototype.kt
│ │ ├── Proxy.kt
│ │ ├── Singleton.kt
│ │ ├── State.kt
│ │ ├── Strategy.kt
│ │ ├── Template Method.kt
│ │ ├── Visitor.kt
│ │ └── Сhain Of Responsibilities.kt
│ ├── other/
│ │ ├── BinaryDigitsCounter.kt
│ │ ├── EuclidAlgorithm.kt
│ │ ├── Factorial.kt
│ │ ├── FactorialAdvanced.kt
│ │ ├── FactorialBigWithCache.kt
│ │ ├── FactorialWithCache.kt
│ │ ├── FizzBuzz.kt
│ │ ├── KnuthMorrisPrattAlgorithm.kt
│ │ ├── LevenshteinLengthAlgorithm.kt
│ │ ├── MaxAlgorithm.kt
│ │ ├── MinAlgorithm.kt
│ │ ├── PalindromeAlgorithm.kt
│ │ ├── ParenthesisCheckAlgorithm.kt
│ │ ├── ReverseArrayAlgorithm.kt
│ │ ├── SieveOfEratosthenesAlgorithm.kt
│ │ ├── Sqrt.kt
│ │ ├── StringEqualsHashAlgorithm.kt
│ │ └── SwapAlgorithm.kt
│ ├── search/
│ │ ├── BinarySearch.kt
│ │ └── LinearSearch.kt
│ ├── sorting/
│ │ ├── BubbleSort.kt
│ │ ├── CountingSort.kt
│ │ ├── InsertionSort.kt
│ │ ├── MergeSort.kt
│ │ ├── QuickSort.kt
│ │ ├── RadixSort.kt
│ │ ├── SelectionSort.kt
│ │ └── TimSort.kt
│ └── structures/
│ ├── BinaryTree.kt
│ ├── CircularLinkedList.kt
│ ├── DoubleLinkedList.kt
│ ├── DynamicArray.kt
│ ├── Graph.kt
│ ├── GraphWithWeights.kt
│ ├── Matrix.kt
│ ├── MaxHeap.kt
│ ├── MinHeap.kt
│ ├── Queue.kt
│ ├── SingleLinkedList.kt
│ ├── Stack1.kt
│ └── Stack2.kt
└── test/
└── kotlin/
├── TestUtils.kt
├── design_patterns/
│ ├── AbstractFactoryTest.kt
│ ├── AdapterTest.kt
│ ├── BridgeTest.kt
│ ├── BuilderTest.kt
│ ├── ChainOfResponsibilitiesTest.kt
│ ├── CommandTest.kt
│ ├── CompositeTest.kt
│ ├── DecoratorTest.kt
│ ├── FacadeTest.kt
│ ├── FactoryMethodTest.kt
│ ├── FlyweightTest.kt
│ ├── InterpreterTest.kt
│ ├── IteratorTest.kt
│ ├── MediatorTest.kt
│ ├── MementoTest.kt
│ ├── ObserverTest.kt
│ ├── PrototypeTest.kt
│ ├── ProxyTest.kt
│ ├── SingletonTest.kt
│ ├── StateTest.kt
│ ├── StrategyTest.kt
│ ├── TemplateMethodTest.kt
│ └── VisitorTest.kt
├── other/
│ ├── BinaryDigitsCounterTest.kt
│ ├── EuclidAlgorithmTest.kt
│ ├── FactorialAdvancedTest.kt
│ ├── FactorialBigWithCacheTest.kt
│ ├── FactorialTest.kt
│ ├── FactorialWithCacheTest.kt
│ ├── FizzBuzzTest.kt
│ ├── KnuthMorrisPrattAlgorithmTest.kt
│ ├── LevenshteinLengthAlgorithmTest.kt
│ ├── MaxAlgorithmTest.kt
│ ├── MinAlgorithmTest.kt
│ ├── PalindromeAlgorithmTest.kt
│ ├── ParenthesisCheckAlgorithmTest.kt
│ ├── ReverseArrayAlgorithmTest.kt
│ ├── SieveOfEratosthenesAlgorithmTest.kt
│ ├── SqrtTest.kt
│ ├── StringEqualsHashAlgorithmTest.kt
│ └── SwapAlgorithmTest.kt
├── search/
│ ├── BinarySearchTest.kt
│ └── LinearSearchTest.kt
├── sorting/
│ ├── BubbleSortTest.kt
│ ├── CountingSortTest.kt
│ ├── InsertionSortTest.kt
│ ├── MergeSortTest.kt
│ ├── QuickSortTest.kt
│ ├── RadixSortTest.kt
│ ├── SelectionSortTest.kt
│ └── TimSortTest.kt
└── structures/
├── BinaryTreeTest.kt
├── CircularLinkedListTest.kt
├── DoubleLinkedListTest.kt
├── DynamicArrayTest.kt
├── GraphTest.kt
├── GraphWithWeightsTest.kt
├── MatrixTest.kt
├── MaxHeapTest.kt
├── MinHeapTest.kt
├── QueueTest.kt
├── SingleLinkedListTest.kt
├── Stack1Test.kt
└── Stack2Test.kt
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# IDE-specific stuff
idea/
# CMake
cmake-build-*/
# File-based project format
*.iws
# IntelliJ
out/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### Kotlin ###
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
### Gradle ###
.gradle
**/build/
!src/**/build/
# Ignore Gradle GUI config
gradle-app.setting
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
# Avoid ignore Gradle wrappper properties
!gradle-wrapper.properties
# Cache of project
.gradletasknamecache
# Eclipse Gradle plugin generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
### Gradle Patch ###
# Java heap dump
*.hprof
# End of https://www.toptal.com/developers/gitignore/api/intellij,gradle,kotlin
================================================
FILE: LICENSE.txt
================================================
MIT License
Copyright (c) 2023 Dmitry Tsyvtsyn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================

# Kotlin Algorithms and Design Patterns
This repository lists the most common algorithms, data structures, and design patterns written in the Kotlin programming language.
All code is divided into separate packages:
1. sorting - sorting algorithms
2. search - search algorithms
3. structures - data structure (lists, arrays, stack, queue, binary trees, e.t.c)
4. design-patterns - design patterns
5. other - other algorithms (Levenshtein distance, Knut Morris Pratt algorithm, e.t.c)
For each code file, tests are made, which are located in the test/kotlin directory
Also, whenever possible, I add *javadoc* for each class, method, and file
Content:
1. package design_patterns - design patterns
* [Abstract Factory](/src/main/kotlin/design_patterns/Abstract%20Factory.kt)
* [Adapter](/src/main/kotlin/design_patterns/Adapter.kt)
* [Bridge](/src/main/kotlin/design_patterns/Bridge.kt)
* [Builder](/src/main/kotlin/design_patterns/Builder.kt)
* [Chain Of Responsibilities](/src/main/kotlin/design_patterns/Сhain%20Of%20Responsibilities.kt)
* [Command](/src/main/kotlin/design_patterns/Command.kt)
* [Composite](/src/main/kotlin/design_patterns/Composite.kt)
* [Decorator](/src/main/kotlin/design_patterns/Decorator.kt)
* [Facade](/src/main/kotlin/design_patterns/Facade.kt)
* [Factory Method](/src/main/kotlin/design_patterns/Factory%20Method.kt)
* [Flyweight](/src/main/kotlin/design_patterns/Flyweight.kt)
* [Interpreter](/src/main/kotlin/design_patterns/Interpreter.kt)
* [Iterator](/src/main/kotlin/design_patterns/Iterator.kt)
* [Mediator](/src/main/kotlin/design_patterns/Mediator.kt)
* [Memento](/src/main/kotlin/design_patterns/Memento.kt)
* [Observer](/src/main/kotlin/design_patterns/Observer.kt)
* [Prototype](/src/main/kotlin/design_patterns/Prototype.kt)
* [Proxy](/src/main/kotlin/design_patterns/Proxy.kt)
* [Singleton](/src/main/kotlin/design_patterns/Singleton.kt)
* [State](/src/main/kotlin/design_patterns/State.kt)
* [Strategy](/src/main/kotlin/design_patterns/Strategy.kt)
* [Template Method](/src/main/kotlin/design_patterns/Template%20Method.kt)
* [Visitor](/src/main/kotlin/design_patterns/Visitor.kt)
2. package structures - data structure
* [Binary tree](/src/main/kotlin/structures/BinaryTree.kt)
* [Stack 1st implementation](/src/main/kotlin/structures/Stack1.kt)
* [Stack 2nd implementation](/src/main/kotlin/structures/Stack2.kt)
* [Queue](/src/main/kotlin/structures/Queue.kt)
* [Undirected Graph](/src/main/kotlin/structures/Graph.kt)
* [Directed Graph with weights](/src/main/kotlin/structures/GraphWithWeights.kt)
* [Matrix](/src/main/kotlin/structures/Matrix.kt)
* [Dynamic Array](/src/main/kotlin/structures/DynamicArray.kt)
* [Single linked list](/src/main/kotlin/structures/SingleLinkedList.kt)
* [Double linked list](/src/main/kotlin/structures/DoubleLinkedList.kt)
* [Min-heap](/src/main/kotlin/structures/MinHeap.kt)
* [Max-heap](/src/main/kotlin/structures/MaxHeap.kt)
3. package sorting - sorting algorithms
* [Bubble sort](/src/main/kotlin/sorting/BubbleSort.kt)
* [Insertion sort](/src/main/kotlin/sorting/InsertionSort.kt)
* [Merge sort](/src/main/kotlin/sorting/MergeSort.kt)
* [Quick sort](/src/main/kotlin/sorting/QuickSort.kt)
* [Selection sort](/src/main/kotlin/sorting/SelectionSort.kt)
* [Radix sort](/src/main/kotlin/sorting/RadixSort.kt)
* [Tim sort](/src/main/kotlin/sorting/TimSort.kt)
* [Count sort](/src/main/kotlin/sorting/CountingSort.kt)
4. package search - search algorithms
* [Binary search](/src/main/kotlin/search/BinarySearch.kt)
* [Linear search](/src/main/kotlin/search/LinearSearch.kt)
5. package other - other algorithms
* [Finite state machine](/src/main/kotlin/other/BinaryDigitsCounter.kt)
* [Euclid's algorithm](/src/main/kotlin/other/EuclidAlgorithm.kt)
* [Factorial](/src/main/kotlin/other/Factorial.kt)
* [Factorial from Google Guava library](/src/main/kotlin/other/FactorialAdvanced.kt)
* [Factorial of BigInteger's with cache](/src/main/kotlin/other/FactorialBigWithCache.kt)
* [Factorial with cache](/src/main/kotlin/other/FactorialWithCache.kt)
* [FizzBuzz](/src/main/kotlin/other/FizzBuzz.kt)
* [Knut Morris Pratt's Algorithm for finding a substring](/src/main/kotlin/other/KnuthMorrisPrattAlgorithm.kt)
* [Levenshtein distance](/src/main/kotlin/other/LevenshteinLengthAlgorithm.kt)
* [Finding the maximum](/src/main/kotlin/other/MaxAlgorithm.kt)
* [Finding the minimum](/src/main/kotlin/other/MinAlgorithm.kt)
* [Palindrome](/src/main/kotlin/other/PalindromeAlgorithm.kt)
* [Parenthesis checking algorithm](/src/main/kotlin/other/ParenthesisCheckAlgorithm.kt)
* [Reverse Array](/src/main/kotlin/other/ReverseArrayAlgorithm.kt)
* [Sieve of Eratosthenes](/src/main/kotlin/other/SieveOfEratosthenesAlgorithm.kt)
* [The square root of a number](/src/main/kotlin/other/Sqrt.kt)
* [StringEqualsHash](/src/main/kotlin/other/StringEqualsHashAlgorithm.kt)
* [Swap algorithm](/src/main/kotlin/other/SwapAlgorithm.kt)
## Your wishes and ideas
If you are interested in my repository or you have ideas on how to improve it or add something write: [Telegram](https://t.me/dmitry_tsyvtsyn), [Gmail](mailto:dmitry.kind.2@gmail.com)
## License
MIT License
Copyright (c) 2023 Dmitry Tsyvtsyn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README_ru.md
================================================

# Kotlin Algorithms and Design Patterns
В этом репозитории приведены наиболее распространенные алгоритмы, структуры данных и паттерны проектирования, написанные на языке программирования Kotlin.
Весь код разбит по отдельным пакетам:
1. ru.sorting - алгоритмы сортировки
2. ru.search - алгоритмы поиска
3. ru.structures - структуры данных (списки, массивы, стэк, очередь, бинарное дерево и др.)
4. design-patterns - паттерны проектирования
5. ru.other - другие алгоритмы (расстояние Левенштейна, алгоритм Кнута Морриса Пратта и т.д.)
Для каждого файла с кодом сделаны тесты, которые находятся в директории test/kotlin
Также по возможности я добавляю *javadoc* для каждого класса, метода и файла
Структура:
1. пакет ru.design_patterns - паттерны проектирования
* [Abstract Factory](/src/main/kotlin/design_patterns/Abstract%20Factory.kt)
* [Adapter](/src/main/kotlin/design_patterns/Adapter.kt)
* [Bridge](/src/main/kotlin/design_patterns/Bridge.kt)
* [Builder](/src/main/kotlin/design_patterns/Builder.kt)
* [Chain Of Responsibilities](/src/main/kotlin/design_patterns/Сhain%20Of%20Responsibilities.kt)
* [Command](/src/main/kotlin/design_patterns/Command.kt)
* [Composite](/src/main/kotlin/design_patterns/Composite.kt)
* [Decorator](/src/main/kotlin/design_patterns/Decorator.kt)
* [Facade](/src/main/kotlin/design_patterns/Facade.kt)
* [Factory Method](/src/main/kotlin/design_patterns/Factory%20Method.kt)
* [Flyweight](/src/main/kotlin/design_patterns/Flyweight.kt)
* [Interpreter](/src/main/kotlin/design_patterns/Interpreter.kt)
* [Iterator](/src/main/kotlin/design_patterns/Iterator.kt)
* [Mediator](/src/main/kotlin/design_patterns/Mediator.kt)
* [Memento](/src/main/kotlin/design_patterns/Memento.kt)
* [Observer](/src/main/kotlin/design_patterns/Observer.kt)
* [Prototype](/src/main/kotlin/design_patterns/Prototype.kt)
* [Proxy](/src/main/kotlin/design_patterns/Proxy.kt)
* [Singleton](/src/main/kotlin/design_patterns/Singleton.kt)
* [State](/src/main/kotlin/design_patterns/State.kt)
* [Strategy](/src/main/kotlin/design_patterns/Strategy.kt)
* [Template Method](/src/main/kotlin/design_patterns/Template%20Method.kt)
* [Visitor](/src/main/kotlin/design_patterns/Visitor.kt)
2. пакет ru.structures - структуры данных
* [Бинарное дерево](/src/main/kotlin/structures/BinaryTree.kt)
* [Стэк 1-ая реализация](/src/main/kotlin/structures/Stack1.kt)
* [Стэк 2-ая реализация](/src/main/kotlin/structures/Stack2.kt)
* [Очередь](/src/main/kotlin/structures/Queue.kt)
* [Неориентированный граф](/src/main/kotlin/structures/Graph.kt)
* [Ориентированный граф с весами](/src/main/kotlin/structures/GraphWithWeights.kt)
* [Матрица](/src/main/kotlin/structures/Matrix.kt)
* [Динамический массив](/src/main/kotlin/structures/DynamicArray.kt)
* [Односвязный список](/src/main/kotlin/structures/SingleLinkedList.kt)
* [Двусвязный список](/src/main/kotlin/structures/DoubleLinkedList.kt)
* [Min-куча](/src/main/kotlin/structures/MinHeap.kt)
* [Max-куча](/src/main/kotlin/structures/MaxHeap.kt)
3. пакет ru.sorting - алгоритмы сортировки
* [Пузырьковая сортировка](/src/main/kotlin/sorting/BubbleSort.kt)
* [Сортировка вставками](/src/main/kotlin/sorting/InsertionSort.kt)
* [Сортировака слиянием](/src/main/kotlin/sorting/MergeSort.kt)
* [Быстрая сортировка](/src/main/kotlin/sorting/QuickSort.kt)
* [Сортировка выбором](/src/main/kotlin/sorting/SelectionSort.kt)
* [Поразрядная сортировка](/src/main/kotlin/sorting/RadixSort.kt)
* [Tim sort](/src/main/kotlin/sorting/TimSort.kt)
* [Сортировка подсчётом](/src/main/kotlin/sorting/CountingSort.kt)
4. пакет ru.search - алгоритмы поиска
* [Бинарный поиск](/src/main/kotlin/search/BinarySearch.kt)
* [Линейный поиск](/src/main/kotlin/search/LinearSearch.kt)
5. пакет ru.other - другие алгоритмы
* [Конечный автомат](/src/main/kotlin/other/BinaryDigitsCounter.kt)
* [Алгоритм Эвклида](/src/main/kotlin/other/EuclidAlgorithm.kt)
* [Факториал](/src/main/kotlin/other/Factorial.kt)
* [Факториал из Google Guava библиотеки](/src/main/kotlin/other/FactorialAdvanced.kt)
* [Факториал BigInteger'ов с кэшем](/src/main/kotlin/other/FactorialBigWithCache.kt)
* [Факториал с кэшем](/src/main/kotlin/other/FactorialWithCache.kt)
* [FizzBuzz](/src/main/kotlin/other/FizzBuzz.kt)
* [Алгоритм Кнута Морриса Пратта для поиска подстроки](/src/main/kotlin/other/KnuthMorrisPrattAlgorithm.kt)
* [Расстояние Левенштейна](/src/main/kotlin/other/LevenshteinLengthAlgorithm.kt)
* [Поиск максимума](/src/main/kotlin/other/MaxAlgorithm.kt)
* [Поиск минимума](/src/main/kotlin/other/MinAlgorithm.kt)
* [Палиндром](/src/main/kotlin/other/PalindromeAlgorithm.kt)
* [Проверка скобок на корректность](/src/main/kotlin/other/ParenthesisCheckAlgorithm.kt)
* [Алгоритм переворота массива](/src/main/kotlin/other/ReverseArrayAlgorithm.kt)
* [Решето Эратосфена](/src/main/kotlin/other/SieveOfEratosthenesAlgorithm.kt)
* [Квадратный корень из числа](/src/main/kotlin/other/Sqrt.kt)
* [Сравнение строк с помощью хэша](/src/main/kotlin/other/StringEqualsHashAlgorithm.kt)
* [Алгоритм обмена двух переменных](/src/main/kotlin/other/SwapAlgorithm.kt)
## Ваши пожелания и идеи
Если вы заинтересовались моим репозиторием или у вас появились идеи как его улучшить или что-то добавить, напишите: [Telegram](https://t.me/rwcwuwr), [Gmail](mailto:dmitry.kind.2@gmail.com)
## Лицензия
MIT License
Copyright (c) 2023 Dmitry Tsyvtsyn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: build.gradle.kts
================================================
plugins {
id("org.jetbrains.kotlin.jvm") version "1.8.22"
}
group = "io.github.dmitrytsyvtsyn.algorithmsdesignpatterns"
version = "1.0.1"
repositories {
mavenCentral()
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib")
testImplementation("junit:junit:4.13.1")
}
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
================================================
FILE: gradle.properties
================================================
kotlin.code.style=official
================================================
FILE: gradlew
================================================
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
================================================
FILE: gradlew.bat
================================================
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: settings.gradle.kts
================================================
rootProject.name = "Kotlin-Algorithms-and-Design-Patterns"
================================================
FILE: src/main/kotlin/design_patterns/Abstract Factory.kt
================================================
package design_patterns
/**
*
* Abstract factory is a generative design pattern that allows
*
* you to create families of related objects without being tied to
*
* the specific classes of objects you create.
*
*/
interface Button {
fun draw() {}
}
class AndroidButton : Button
class IOSButton : Button
interface Text {
fun draw() {}
}
class AndroidText : Text
class IOSText : Text
interface ButtonFactory {
fun createButton() : Button
fun createText() : Text
}
class AndroidButtonFactory : ButtonFactory {
override fun createButton() : Button = AndroidButton()
override fun createText(): Text = AndroidText()
}
class IOSButtonFactory : ButtonFactory {
override fun createButton() : Button = IOSButton()
override fun createText(): Text = IOSText()
}
================================================
FILE: src/main/kotlin/design_patterns/Adapter.kt
================================================
package design_patterns
/**
*
* Adapter is a structural design pattern that allows objects with incompatible interfaces to work together
*
*/
interface EnglishSpeaker {
fun speakEnglish(): String
}
class EnglishSpeakerImpl : EnglishSpeaker {
override fun speakEnglish(): String {
return "Hello, friend!"
}
}
interface SpainSpeaker {
fun speakSpanish(): String
}
class SpainSpeakerAdapter(private val englishSpeaker: EnglishSpeaker) : SpainSpeaker {
override fun speakSpanish(): String =
when (englishSpeaker.speakEnglish()) {
"Hello, friend!" -> "Hola, amigo!"
else -> "No te entiendo"
}
}
================================================
FILE: src/main/kotlin/design_patterns/Bridge.kt
================================================
package design_patterns
/**
*
* Bridge is a structural design pattern used to separate abstraction and implementation
*
* so they can change independently
*
*/
// OperatingSystem implements an internal algorithm for drawing primitives (operating systems are implementations in this example)
abstract class OperatingSystem(private val name: String, private val version: Int) {
protected val lines = mutableListOf()
protected val circles = mutableListOf()
abstract fun drawLine(startX: Int, startY: Int, endX: Int, endY: Int)
abstract fun drawCircle(centerX: Int, centerY: Int, radius: Int)
override fun toString(): String {
return """
$name $version
Lines:
${lines.joinToString("\n")}
Circles:
${circles.joinToString("\n")}
""".trimIndent()
}
}
// different implementations have different algorithms for drawing primitives
class WindowsSystem : OperatingSystem("Windows", 10) {
override fun drawLine(startX: Int, startY: Int, endX: Int, endY: Int) {
lines.add("Windows graphic subsystem -> startX: $startX, startY: $startY, endX: $endX, endY: $endY")
}
override fun drawCircle(centerX: Int, centerY: Int, radius: Int) {
circles.add("Windows graphic subsystem -> centerX: $centerX, centerY: $centerY, radius: $radius")
}
}
class MacOSSystem : OperatingSystem("MacOS", 14) {
override fun drawLine(startX: Int, startY: Int, endX: Int, endY: Int) {
lines.add("MacOS graphic subsystem -> startX: $startX, startY: $startY, endX: $endX, endY: $endY")
}
override fun drawCircle(centerX: Int, centerY: Int, radius: Int) {
circles.add("MacOS graphic subsystem -> centerX: $centerX, centerY: $centerY, radius: $radius")
}
}
// we can add new primitives without changing OperatingSystem implementations (primitives are abstractions in this example)
abstract class GraphicPrimitive {
abstract fun draw(system: OperatingSystem)
}
class GraphicCirclePrimitive(
private val centerX: Int,
private val centerY: Int,
private val radius: Int
) : GraphicPrimitive() {
override fun draw(system: OperatingSystem) {
system.drawCircle(centerX, centerY, radius)
}
}
class GraphicLinePrimitive(
private val startX: Int,
private val startY: Int,
private val endX: Int,
private val endY: Int
) : GraphicPrimitive() {
override fun draw(system: OperatingSystem) {
system.drawLine(startX, startY, endX, endY)
}
}
================================================
FILE: src/main/kotlin/design_patterns/Builder.kt
================================================
package design_patterns
/**
*
* Builder is is a generative design pattern that is used to create complex objects,
*
* separates the construction of an object from its representation
*
*/
/**
* The first variant
*/
class HttpConnectionClient1 private constructor(
private val dnsServerAddress: String,
private val callTimeout: Int,
private val connectTimeout: Int,
private val readTimeout: Int,
private val writeTimeout: Int,
// class can have many more fields
) {
override fun toString() = """
dns -> $dnsServerAddress
call timeout -> $callTimeout
connect timeout -> $connectTimeout
read timeout -> $readTimeout
write timeout -> $writeTimeout
""".trimIndent()
class Builder {
private var dnsServerAddress: String = "8.8.8.8"
private var callTimeout: Int = 0
private var connectTimeout: Int = 10_000
private var readTimeout: Int = 10_000
private var writeTimeout: Int = 0
fun dnsServerAddress(address: String) = apply {
dnsServerAddress = address
}
fun callTimeout(timeout: Int) = apply {
// we can add some checks such as:
// if (timeout < 0) throw IllegalArgumentException("Uncorrected timeout: $timeout")
callTimeout = timeout
}
fun connectTimeout(timeout: Int) = apply {
connectTimeout = timeout
}
fun readTimeout(timeout: Int) = apply {
readTimeout = timeout
}
fun writeTimeout(timeout: Int) = apply {
writeTimeout = timeout
}
fun build() = HttpConnectionClient1(dnsServerAddress, callTimeout, connectTimeout, readTimeout, writeTimeout)
}
}
/**
* The second variant
*/
class HttpConnectionClient2 private constructor() {
private var dnsServerAddress: String = "8.8.8.8"
private var callTimeout: Int = 0
private var connectTimeout: Int = 10_000
private var readTimeout: Int = 10_000
private var writeTimeout: Int = 0
override fun toString() = """
dns -> $dnsServerAddress
call timeout -> $callTimeout
connect timeout -> $connectTimeout
read timeout -> $readTimeout
write timeout -> $writeTimeout
""".trimIndent()
companion object {
fun newBuilder() = HttpConnectionClient2().Builder()
}
inner class Builder {
fun dnsServerAddress(address: String) = apply {
dnsServerAddress = address
}
fun callTimeout(timeout: Int) = apply {
// we can add some checks such as:
// if (timeout < 0) throw IllegalArgumentException("Uncorrected timeout: $timeout")
callTimeout = timeout
}
fun connectTimeout(timeout: Int) = apply {
connectTimeout = timeout
}
fun readTimeout(timeout: Int) = apply {
readTimeout = timeout
}
fun writeTimeout(timeout: Int) = apply {
writeTimeout = timeout
}
fun build() = this@HttpConnectionClient2
}
}
/**
* Kotlin variant with default arguments
*/
class HttpConnectionClient3(
private val dnsServerAddress: String = "8.8.8.8",
private val callTimeout: Int = 0,
private val connectTimeout: Int = 10_000,
private val readTimeout: Int = 10_000,
private val writeTimeout: Int = 0
) {
override fun toString() = """
dns -> $dnsServerAddress
call timeout -> $callTimeout
connect timeout -> $connectTimeout
read timeout -> $readTimeout
write timeout -> $writeTimeout
""".trimIndent()
}
================================================
FILE: src/main/kotlin/design_patterns/Command.kt
================================================
package design_patterns
/**
*
* Command is a behavioral pattern that encapsulates a request to perform an action as a separate object
*
*/
// StereoSystem is the receiver that performs the action
class StereoSystem {
private var hasTurnedOn = false
private var volume = 50
val currentState: String
get() = """
running status: $hasTurnedOn
volume value: $volume
""".trimIndent()
fun turnOn() {
hasTurnedOn = true
}
fun turnOff() {
hasTurnedOn = false
}
fun increaseVolume() {
if (!hasTurnedOn) return
if (volume < 100) {
volume += 10
}
}
fun decreaseVolume() {
if (!hasTurnedOn) return
if (volume > 0) {
volume -= 10
}
}
}
interface StereoSystemCommand {
fun execute()
fun undo() : Boolean
}
// this command encapsulates a request to increase the volume in StereoSystem
class IncreaseVolumeCommand(private val stereoSystem: StereoSystem) : StereoSystemCommand {
override fun execute() {
stereoSystem.increaseVolume()
}
override fun undo(): Boolean {
stereoSystem.decreaseVolume()
return true
}
}
// this command encapsulates a request to decrease the volume in StereoSystem
class DecreaseVolumeCommand(private val stereoSystem: StereoSystem) : StereoSystemCommand {
override fun execute() {
stereoSystem.decreaseVolume()
}
override fun undo(): Boolean {
stereoSystem.increaseVolume()
return true
}
}
// this command encapsulates a request to turn on StereoSystem
class TurnOnCommand(private val stereoSystem: StereoSystem) : StereoSystemCommand {
override fun execute() {
stereoSystem.turnOn()
}
override fun undo(): Boolean {
stereoSystem.turnOff()
return true
}
}
// this command encapsulates a request to turn off StereoSystem
class TurnOffCommand(private val stereoSystem: StereoSystem) : StereoSystemCommand {
override fun execute() {
stereoSystem.turnOff()
}
override fun undo() = false
}
// we can also create the command that combines others
class MacroCommand(private vararg val commands: StereoSystemCommand) : StereoSystemCommand {
override fun execute() {
for (command in commands) {
command.execute()
}
}
override fun undo(): Boolean {
for (command in commands.reversed()) {
val isNotCancelableCommand = !command.undo()
if (isNotCancelableCommand) return false
}
return true
}
}
// StereoSystemRemoteControl executes commands without breaking their encapsulation
class StereoSystemRemoteControl(private val buttons: Map = mapOf()) {
// we only know about StereoSystemCommand interface
private val commandHistory = mutableListOf()
fun pressButton(name: String) {
val command = buttons[name]
if (command != null) {
command.execute()
commandHistory.add(command)
}
}
fun pressUndoButton() {
val lastCommand = commandHistory.removeLastOrNull()
if (lastCommand != null) {
val isNotCancelableCommand = !lastCommand.undo()
if (isNotCancelableCommand) commandHistory.clear()
}
}
}
================================================
FILE: src/main/kotlin/design_patterns/Composite.kt
================================================
package design_patterns
/**
*
* Composite is a structural design pattern that organizes objects into a tree structure
*
* and allows clients to access individual objects and groups of objects in the same way.
*
*/
// all components have a common interface
abstract class MenuComponent(val title: String) {
// menus and items can give information about themselves
abstract fun fetchMenuInformation() : String
}
class Menu(title: String) : MenuComponent(title) {
// menu can contain other menus and items
private val childMenuComponents = mutableListOf()
// addComponent/removeComponent operations are only available for the menu
fun addComponent(component: MenuComponent) {
childMenuComponents.add(component)
}
fun removeComponent(component: MenuComponent) {
childMenuComponents.remove(component)
}
override fun fetchMenuInformation(): String {
val builder = StringBuilder()
builder.append("Menu: $title")
childMenuComponents.forEach { component ->
builder.append("\n")
builder.append(component.fetchMenuInformation())
}
return builder.toString()
}
}
// the simple component that contains no others
class MenuItem(title: String, private val price: Int) : MenuComponent(title) {
override fun fetchMenuInformation(): String =
"""
title: $title
price: $price
-------------
""".trimIndent()
}
================================================
FILE: src/main/kotlin/design_patterns/Decorator.kt
================================================
package design_patterns
/**
*
* Decorator is a structural design pattern that adds new functionality to an object:
*
* classes implement a common interface and to extend the functionality of the previous object,
*
* the old object is passed through the constructor
*
*/
interface MyPrinter {
fun printedText() : String
}
// just returns "Hello"
class HelloPrinter : MyPrinter {
override fun printedText() : String {
return "Hello"
}
}
// adds a comma to the previous value of the printedText() function
class CommaPrinter(private val printer: MyPrinter) : MyPrinter {
override fun printedText() : String {
return "${printer.printedText()},"
}
}
// adds a space to the previous value of the printedText() function
class SpacePrinter(private val printer: MyPrinter) : MyPrinter {
override fun printedText() : String {
return "${printer.printedText()} "
}
}
// adds the word "World" to the previous value of the printedText() function
class WorldPrinter(private val printer: MyPrinter) : MyPrinter {
override fun printedText() : String {
return "${printer.printedText()}World"
}
}
// adds an exclamation mark to the previous value of the printedText() function
class ExclamationPrinter(private val printer: MyPrinter) : MyPrinter {
override fun printedText() : String {
return "${printer.printedText()}!"
}
}
================================================
FILE: src/main/kotlin/design_patterns/Facade.kt
================================================
package design_patterns
/**
*
* Facade is a structural design pattern that simplifies the interface to a group of interfaces
*
* with a more complex implementation
*
*/
data class GoodsEntity(
private val id: Long,
private val name: String,
private val description: String,
private val price: Double
)
class GoodsDatabase {
private val cachedGoods = mutableListOf()
fun save(goods: List) {
cachedGoods.addAll(goods)
}
fun read() = cachedGoods
}
class GoodsNetworkService {
fun fetch() = listOf(
GoodsEntity(
id = 1,
name = "Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software 2nd Edition",
description = "You know you don't want to reinvent the wheel, so you look to Design Patterns: the lessons learned by those who've faced the same software design problems.",
price = 41.94
)
)
}
data class CategoryEntity(
private val id: Long,
private val name: String
)
class CategoryDatabase {
private val cachedCategories = mutableListOf()
fun save(goods: List) {
cachedCategories.addAll(goods)
}
fun read() = cachedCategories
}
class CategoryNetworkService {
fun fetch() = listOf(
CategoryEntity(
id = 1,
name = "Books"
)
)
}
data class GoodsResult(
val goods: List,
val categories: List
)
// we have a group of interfaces (databases and network services)
class GoodsRepository(
private val goodsDatabase: GoodsDatabase,
private val goodsNetworkService: GoodsNetworkService,
private val categoryDatabase: CategoryDatabase,
private val categoryNetworkService: CategoryNetworkService
) {
// we need a simpler interface
fun goodsAndCategories() : GoodsResult {
val goods = goodsDatabase.read().toMutableList()
if (goods.isEmpty()) {
val networkGoods = goodsNetworkService.fetch()
goodsDatabase.save(networkGoods)
goods.addAll(networkGoods)
}
val categories = categoryDatabase.read().toMutableList()
if (categories.isEmpty()) {
val networkCategories = categoryNetworkService.fetch()
categoryDatabase.save(networkCategories)
categories.addAll(networkCategories)
}
return GoodsResult(
goods = goods,
categories = categories
)
}
}
================================================
FILE: src/main/kotlin/design_patterns/Factory Method.kt
================================================
package design_patterns
/**
*
* A factory method is a generic design pattern that defines
*
* a common interface for creating objects in a superclass,
*
* allowing subclasses to change the type of objects they create.
*
*/
abstract class House(private val address: String, private val price: Int) {
override fun toString() = """
address = $address
price = $price
""".trimIndent()
}
// the factory method makes sense if we have a hierarchy of objects
class WoodenCheapHouse(address: String) : House(address, 50_000)
class WoodenAverageHouse(address: String) : House(address, 250_000)
class WoodenExpensiveHouse(address: String) : House(address, 1_000_000)
class StoneCheapHouse(address: String) : House(address, 45_000)
class StoneAverageHouse(address: String) : House(address, 230_000)
class StoneExpensiveHouse(address: String) : House(address, 900_000)
// we have a common logic for every HouseCompany
abstract class HouseCompany {
private val alreadyBuiltHouses = mutableListOf()
val examplesAlreadyBuiltHouses: String
get() = alreadyBuiltHouses.joinToString("\n\n")
fun orderHouse(address: String, cost: HouseCompanyCost): House {
val house = buildHouse(address, cost)
alreadyBuiltHouses.add(house)
return house
}
// the subclasses define a specific implementation
protected abstract fun buildHouse(address: String, cost: HouseCompanyCost): House
enum class HouseCompanyCost { CHEAP, AVERAGE, EXPENSIVE }
}
// WoodenHouseCompany only builds wooden houses
class WoodenHouseCompany : HouseCompany() {
override fun buildHouse(address: String, cost: HouseCompanyCost) = when(cost) {
HouseCompanyCost.CHEAP -> WoodenCheapHouse(address)
HouseCompanyCost.AVERAGE -> WoodenAverageHouse(address)
HouseCompanyCost.EXPENSIVE -> WoodenExpensiveHouse(address)
}
}
// StoneHouseCompany only builds stone houses
class StoneHouseCompany : HouseCompany() {
override fun buildHouse(address: String, cost: HouseCompanyCost) = when(cost) {
HouseCompanyCost.CHEAP -> StoneCheapHouse(address)
HouseCompanyCost.AVERAGE -> StoneAverageHouse(address)
HouseCompanyCost.EXPENSIVE -> StoneExpensiveHouse(address)
}
}
================================================
FILE: src/main/kotlin/design_patterns/Flyweight.kt
================================================
package design_patterns
/**
*
* Flyweight is a structural design pattern that reduces memory costs by reusing a family of objects
*
* and storing mutable state outside the object.
*
*/
class BeautifulGarden {
// we reuse objects with immutable state, in this example trees
private val existingTrees = mutableListOf()
// mutable state (coordinates) are stored outside the object
private val placedTrees = mutableListOf>()
fun placeTree(name: String, description: String, height: Int, x: Int, y: Int) {
// check if such a tree already exists reuse it otherwise create a new one
val tree = existingTrees.find { tree -> tree.name == name && tree.description == description && tree.height == height }
?: Tree(name, description, height).apply(existingTrees::add)
placedTrees.add(Triple(x, y, tree))
}
fun placedTreesAsString(): String {
val builder = StringBuilder()
builder.append("Beautiful Garden:\n")
placedTrees.forEach { (x, y, tree) ->
builder.append("name: ${tree.name}, height: ${tree.height}, x: $x, y: $y\n")
}
builder.append("-|-|-|-|-|-|-|-|-|-|-")
return builder.toString()
}
data class Tree(
val name: String,
val description: String,
val height: Int
)
}
================================================
FILE: src/main/kotlin/design_patterns/Interpreter.kt
================================================
package design_patterns
/**
*
* Interpreter is a behavioral design pattern that defines a simple language grammar for a problem domain,
*
* represents grammatical rules as language sentences and interprets them to solve commonly encountered problems
*
*/
// contains general information for the interpreter
class InterpreterContext {
private val variables = mutableMapOf()
fun putVariable(key: String, value: Int) {
variables[key] = value
}
fun fetchVariable(key: String): Int {
return variables[key] ?: 0
}
}
// represents a specific interpreter grammar expression
interface InterpreterExpression {
fun interpret(context: InterpreterContext)
}
class SetIntVariableExpression(
private val key: String,
private val intValue: Int
) : InterpreterExpression {
override fun interpret(context: InterpreterContext) {
context.putVariable(key = key, value = intValue)
}
}
class PerformExpression(private vararg val expressions: InterpreterExpression) : InterpreterExpression {
override fun interpret(context: InterpreterContext) {
expressions.forEach { it.interpret(context) }
}
}
class AddVariablesExpression(
private val key0: String,
private val key1: String,
private val result: String
) : InterpreterExpression {
override fun interpret(context: InterpreterContext) {
context.putVariable(
key = result,
value = context.fetchVariable(key0) + context.fetchVariable(key1)
)
}
}
class MultipleVariablesExpression(
private val key0: String,
private val key1: String,
private val result: String
) : InterpreterExpression {
override fun interpret(context: InterpreterContext) {
context.putVariable(
key = result,
value = context.fetchVariable(key0) * context.fetchVariable(key1)
)
}
}
================================================
FILE: src/main/kotlin/design_patterns/Iterator.kt
================================================
package design_patterns
/**
*
* Iterator is a behavioral design pattern that provides a mechanism for sequentially enumerating the elements
*
* of a collection without revealing its internal representation.
*
*/
interface BoxIterator {
fun hasNext(): Boolean
fun next(): T
}
interface BoxIterable {
fun iterator(): BoxIterator
}
class GiftBox(private val presents: Array) : BoxIterable {
override fun iterator() = object : BoxIterator {
private var current = -1
override fun next(): String {
return presents[current]
}
override fun hasNext(): Boolean {
if (current < presents.size - 1) {
current++
return true
}
return false
}
}
}
================================================
FILE: src/main/kotlin/design_patterns/Mediator.kt
================================================
package design_patterns
/**
*
* Mediator is a behavioral design pattern that reduces the coupling of many classes among themselves
*
* by moving these couplings into one mediator class
*
*/
// SoftwareDevelopmentManager is a mediator for the customer, designer, programmer and tester
class SoftwareDevelopmentManager {
private lateinit var customer: SoftwareDevelopmentMember
private lateinit var designer: SoftwareDevelopmentMember
private lateinit var programmer: SoftwareDevelopmentMember
private lateinit var tester: SoftwareDevelopmentMember
fun changeCustomer(member: SoftwareDevelopmentMember) { customer = member }
fun changeDesigner(member: SoftwareDevelopmentMember) { designer = member }
fun changeProgrammer(member: SoftwareDevelopmentMember) { programmer = member }
fun changeTester(member: SoftwareDevelopmentMember) { tester = member }
private val stages = mutableListOf()
val stagesAsString: String
get() = stages.joinToString("\n")
// members do not interact directly with each other because the mediator does it
// which reduces the coupling between them
fun nextStage(work: String, member: SoftwareDevelopmentMember) {
val finishedStage = when (member) {
is CustomerSoftwareDevelopmentMember -> designer.receiveWork(work)
is DesignerSoftwareDevelopmentMember -> programmer.receiveWork(work)
is ProgrammerSoftwareDevelopmentMember -> tester.receiveWork(work)
is TesterSoftwareDevelopmentMember -> customer.receiveWork(work)
else -> ""
}
stages.add(finishedStage)
}
}
// SoftwareDevelopmentMember works with other members through the mediator
abstract class SoftwareDevelopmentMember(protected val mediator: SoftwareDevelopmentManager) {
abstract fun receiveWork(work: String): String
abstract fun finishWork()
}
class CustomerSoftwareDevelopmentMember(mediator: SoftwareDevelopmentManager) : SoftwareDevelopmentMember(mediator) {
override fun receiveWork(work: String) = "Customer accepted the work: $work"
override fun finishWork() {
mediator.nextStage("design development", this)
}
}
class DesignerSoftwareDevelopmentMember(mediator: SoftwareDevelopmentManager) : SoftwareDevelopmentMember(mediator) {
override fun receiveWork(work: String) = "Designer accepted the work: $work"
override fun finishWork() {
mediator.nextStage("writing code", this)
}
}
class ProgrammerSoftwareDevelopmentMember(mediator: SoftwareDevelopmentManager) : SoftwareDevelopmentMember(mediator) {
override fun receiveWork(work: String) = "Programmer accepted the work: $work"
override fun finishWork() {
mediator.nextStage("application testing", this)
}
}
class TesterSoftwareDevelopmentMember(mediator: SoftwareDevelopmentManager) : SoftwareDevelopmentMember(mediator) {
override fun receiveWork(work: String) = "Tester accepted the work: $work"
override fun finishWork() {
mediator.nextStage("business valuation", this)
}
}
================================================
FILE: src/main/kotlin/design_patterns/Memento.kt
================================================
package design_patterns
/**
*
* Memento is a behavioral design pattern that allows without violating encapsulation to capture
*
* and save the internal state of an object so that it can be restored to this state later
*
*/
class Bundle(val str: String)
// Android system saves the application state in special bundles
// I gave this as an example, Android system’s saving mechanism is much more complicated
class AndroidSystem {
private var savedBundle: Bundle = Bundle("")
fun saveBundle(bundle: Bundle) {
savedBundle = bundle
}
fun restoreBundle() = savedBundle
}
// TextView is an Android component that draws text on the screen
class TextView {
private var currentText: String = ""
fun setText(text: String) {
currentText = text
}
fun text() = currentText
fun draw() {
println(currentText)
}
// saves the current state of TextView before re-creating it
fun onSaveInstanceState(): Bundle {
return Bundle(currentText)
}
// restores the current state after TextView is recreated
fun onRestoreInstanceState(bundle: Bundle) {
currentText = bundle.str
}
}
================================================
FILE: src/main/kotlin/design_patterns/Observer.kt
================================================
package design_patterns
/**
*
* Observer is is a behavioral design pattern that defines a one-to-many relationship between objects
*
* such that when the state of one object changes all dependent objects are automatically notified and updated
*
*/
fun interface PonyObserver {
fun update(item: List)
}
interface PonyObservable {
fun addObserver(observer: PonyObserver)
fun removeObserver(observer: PonyObserver)
fun notifyObservers()
}
// PonyList contains some data and when it changes we will notify observers
class PonyList : PonyObservable {
private val ponies = mutableListOf()
private val observers = mutableSetOf()
fun add(pony: String) {
ponies.add(pony)
// notify observers that the data has changed
notifyObservers()
}
override fun addObserver(observer: PonyObserver) {
observers.add(observer)
}
override fun removeObserver(observer: PonyObserver) {
observers.remove(observer)
}
override fun notifyObservers() {
observers.forEach { observer -> observer.update(ponies) }
}
}
================================================
FILE: src/main/kotlin/design_patterns/Prototype.kt
================================================
package design_patterns
/**
*
* Prototype is a generative design pattern that allows you to copy objects
*
* without going into the details of their implementation.
*
*/
abstract class Sweets(
protected val title: String,
protected val description: String,
protected val price: Int
) {
// we only have a copy interface and don't know about its implementation
abstract fun copy(): Sweets
}
class OreoCookies(
title: String,
private val flavor: String,
price: Int
) : Sweets(
title = title,
price = price,
description = "Take a delicious break with OREO Chocolate Sandwich Cookies, America's favorite sandwich cookie for over 100 years..."
) {
// each implementation creates its own copy
override fun copy(): Sweets {
return OreoCookies(title, flavor, price)
}
override fun equals(other: Any?): Boolean {
if (other == null) return false
if (this === other) return true
if (other !is OreoCookies) return false
return title == other.title && description == other.description &&
flavor == other.flavor && price == other.price
}
}
class `M&MsChocolate`(
private val taste: String,
price: Int,
) : Sweets(
title = "M&M's chocolate",
price = price,
description = "M&M's are a chocolate jelly bean produced by Mars LLC. It first appeared in the United States in 1941 and is now sold in more than 100 countries..."
) {
override fun copy(): Sweets {
return `M&MsChocolate`(taste, price)
}
override fun equals(other: Any?): Boolean {
if (other == null) return false
if (this === other) return true
if (other !is `M&MsChocolate`) return false
return title == other.title && description == other.description &&
taste == other.taste && price == other.price
}
}
================================================
FILE: src/main/kotlin/design_patterns/Proxy.kt
================================================
package design_patterns
/**
*
* Proxy is a structural design pattern that provides an object
*
* that controls access to another object by intercepting all calls.
*
* There are several types of this pattern:
*
* 1) Logging proxy - saves all calls to a real object with their parameters to the log (shown in this example)
* 2) Remote proxy - provides communication with an object which is located in a different address space or on a remote machine (Java Remote Procedure Call)
* 3) Virtual proxy - ensures that a real object is created only when it is actually needed (shown in this example)
* 4) Protection proxy - checks whether the caller has the necessary rights to execute the request
* 5) Caching proxy - provides temporary storage of calculation results
* 6) Synchronizing proxy - performs synchronized access control to an object in a multi-threaded environment (Collections.synchronized** methods)
* 7) Smart reference proxy - performs additional actions when a link is created to an object
*
*/
interface AudioPlayer {
val currentState: String
fun play(audio: String)
fun pause()
fun resume()
fun stop()
}
// we have the simple player simulation
class AudioPlayerImpl : AudioPlayer {
private var currentAudio: String = ""
private var currentStatus = MediaPlayerStatus.NOT_INITIALIZED
override val currentState: String
get() = """
current audio: $currentAudio
current status: $currentStatus
""".trimIndent()
override fun play(audio: String) {
if (audio.isNotBlank()) {
currentAudio = audio
currentStatus = MediaPlayerStatus.RUNNING
}
}
override fun pause() {
if (currentStatus == MediaPlayerStatus.RUNNING) {
currentStatus = MediaPlayerStatus.PAUSED
}
}
override fun resume() {
if (currentStatus == MediaPlayerStatus.PAUSED) {
currentStatus = MediaPlayerStatus.RUNNING
}
}
override fun stop() {
if (currentStatus != MediaPlayerStatus.NOT_INITIALIZED) {
currentAudio = ""
currentStatus = MediaPlayerStatus.NOT_INITIALIZED
}
}
enum class MediaPlayerStatus {
NOT_INITIALIZED, PAUSED, RUNNING
}
}
// MediaPlayerProxy defers the creation of a real object (virtual proxy) and logs all its calls (logging proxy)
class AudioPlayerProxy : AudioPlayer {
// deferred creation of the real player
private val player: AudioPlayer by lazy { AudioPlayerImpl() }
override val currentState: String
get() = player.currentState
override fun play(audio: String) {
player.play(audio)
// logs real player calls
println("play audio: $audio")
}
override fun pause() {
player.pause()
println("pause")
}
override fun resume() {
player.resume()
println("resume")
}
override fun stop() {
player.stop()
println("stop")
}
}
================================================
FILE: src/main/kotlin/design_patterns/Singleton.kt
================================================
package design_patterns
/**
*
* Singleton is a generative design pattern that guarantees the existence of one instance of a class
*
* and provides a global access point to it
*
*/
object SQLiteDatabase {
// SQLiteDatabase instance state
private var connectionId = -1
// These methods provide a global access point to SQLiteDatabase instance state
fun openConnection() {
if (connectionId < 0) {
// open connection...
connectionId = 1
}
}
fun execSQL(sql: String): List {
if (connectionId < 0) return emptyList()
return when (sql) {
"select * from names" -> listOf("Rick", "Morty", "Jerry", "Beth")
else -> emptyList()
}
}
fun closeConnection() {
if (connectionId > 0) {
// close connection...
connectionId = -1
}
}
}
================================================
FILE: src/main/kotlin/design_patterns/State.kt
================================================
package design_patterns
/**
*
* State is a behavioral design pattern that controls changes in the behavior of an object
*
* when its internal state changes
*
*/
// the common interface for all states
interface CocaColaState {
fun insertDollar() : Boolean
fun takeBackDollar() : Boolean
fun pressButton(numberOfDrinks: Int) : Boolean
}
// we don't have drinks in the machine
class EmptyCocaColaState : CocaColaState {
override fun insertDollar() = false
override fun takeBackDollar() = false
override fun pressButton(numberOfDrinks: Int) = false
override fun toString(): String = "EmptyCocaColaState"
}
// we have drinks, but we don't have a dollar in the machine
class NoDollarCocaColaState(private val machine: CocaColaMachine) : CocaColaState {
override fun insertDollar(): Boolean {
machine.setState(HaveDollarCocaColaState(machine))
return true
}
override fun takeBackDollar() = false
override fun pressButton(numberOfDrinks: Int) = false
override fun toString(): String = "NoDollarCocaColaState"
}
// we have a dollar in the machine
class HaveDollarCocaColaState(private val machine: CocaColaMachine) : CocaColaState {
override fun insertDollar() = false
override fun takeBackDollar(): Boolean {
machine.setState(NoDollarCocaColaState(machine))
return true
}
override fun pressButton(numberOfDrinks: Int): Boolean {
if (numberOfDrinks == 1) {
machine.setState(EmptyCocaColaState())
} else {
machine.setState(NoDollarCocaColaState(machine))
}
return true
}
override fun toString(): String = "HaveDollarCocaColaState"
}
// CocaColaMachine switches between states
class CocaColaMachine {
private var numberOfDrinks = 3
private var state: CocaColaState = NoDollarCocaColaState(this)
val currentState: String
get() = state.toString()
fun insertDollar() = state.insertDollar()
fun takeBackDollar() = state.takeBackDollar()
fun pressButton(): Boolean {
val isSuccess = state.pressButton(numberOfDrinks)
if (isSuccess) {
numberOfDrinks -= 1
}
return isSuccess
}
fun loadDrinks(count: Int) {
numberOfDrinks += count
if (numberOfDrinks > 0) {
setState(NoDollarCocaColaState(this))
} else {
setState(EmptyCocaColaState())
}
}
fun setState(newState: CocaColaState) {
state = newState
}
}
================================================
FILE: src/main/kotlin/design_patterns/Strategy.kt
================================================
package design_patterns
/**
*
* Strategy is a behavioral design pattern used to define a family of algorithms,
*
* encapsulate each one and make them interchangeable
*
*/
// encapsulates the filtering algorithm
interface FoodFilterStrategy {
fun filter(items: List): List
}
class OnlyChipsFilterStrategy : FoodFilterStrategy {
override fun filter(items: List): List {
return items.filter { it.category == "chips" }
}
}
class OnlyChocolateFilterStrategy : FoodFilterStrategy {
override fun filter(items: List): List {
return items.filter { it.category == "chocolate" }
}
}
class PriceFilterStrategy(private val price: Int) : FoodFilterStrategy {
override fun filter(items: List): List {
return items.filter { it.price >= price }
}
}
class SearchWordFilterStrategy(private val search: String) : FoodFilterStrategy {
override fun filter(items: List): List {
return items.filter { it.title.contains(search, ignoreCase = true) }
}
}
data class FoodEntity(
val title: String,
val price: Int,
val category: String
)
// FoodStore returns a list of food filtered by strategy
class FoodStore(private var filterStrategy: FoodFilterStrategy) {
// we can change strategy
fun changeStrategy(strategy: FoodFilterStrategy) {
filterStrategy = strategy
}
fun foodItems(): List {
val foodItems = fetchFoodItems()
return filterStrategy.filter(foodItems)
}
private fun fetchFoodItems() =
listOf(
FoodEntity(
"Lays Potato Chips Fried Crab Flavor",
2,
"chips"
),
FoodEntity(
"Lay's Potato Chips, Classic",
3,
"chips"
),
FoodEntity(
"Dove Chocolate",
3,
"chocolate"
),
FoodEntity(
"Ritter Sport Chocolate",
4,
"chocolate"
)
)
}
================================================
FILE: src/main/kotlin/design_patterns/Template Method.kt
================================================
package design_patterns
/**
*
* Template method a behavioral design pattern that defines the basis of an algorithm
*
* and allows subclasses to redefine some steps of the algorithm without changing its overall structure
*
*/
data class Cake(
val layers: List,
val cream: String,
val sprinkles: String
)
abstract class CakeBaker {
protected abstract fun layer(): String
protected abstract fun cream(): String
protected abstract fun sprinkles(): String
// we have the basis of an algorithm
fun makeCake(numberOfLayers: Int): Cake {
return Cake(
layers = List(numberOfLayers) { layer() },
cream = cream(),
sprinkles = sprinkles()
)
}
}
class ChocolateCakeBaker : CakeBaker() {
// subclasses redefines some steps of the algorithm
override fun cream(): String = "chocolate cream"
override fun layer(): String = "chocolate cake layer"
override fun sprinkles(): String = "chocolate chips"
}
class WaffleCakeBaker : CakeBaker() {
override fun cream(): String = "custard cream"
override fun layer(): String = "waffle cake layer"
override fun sprinkles(): String = "coconut flakes"
}
================================================
FILE: src/main/kotlin/design_patterns/Visitor.kt
================================================
package design_patterns
/**
*
* Visitor is a behavioral design pattern that allows you to add a new operation
*
* to an entire class hierarchy without changing the code of these classes.
*
*/
interface PonyVisitor {
fun visitPonies(vararg ponies: LittlePony) : String
fun visitEarthPony(pony: EarthPony) : String
fun visitUnicorn(pony: Unicorn) : String
fun visitPegasus(pony: Pegasus) : String
}
class JsonVisitor : PonyVisitor {
override fun visitPonies(vararg ponies: LittlePony) : String {
val poniesString = ponies.joinToString(",\n") { pony -> pony.accept(this) }
return "[$poniesString]"
}
override fun visitEarthPony(pony: EarthPony): String {
return """
{
"what" : "earth pony",
"name" : "${pony.name()}",
"cutie_mark" : "${pony.cutie()}
}
""".trimIndent()
}
override fun visitUnicorn(pony: Unicorn): String {
return """
{
"what" : "unicorn",
"name" : "${pony.name()}",
"cutie_mark" : "${pony.cutie()}
}
""".trimIndent()
}
override fun visitPegasus(pony: Pegasus): String {
return """
{
"what" : "pegasus",
"name" : "${pony.name()}",
"cutie_mark" : "${pony.cutie()}
}
""".trimIndent()
}
}
class XmlVisitor : PonyVisitor {
override fun visitPonies(vararg ponies: LittlePony) : String {
val poniesString = ponies.joinToString("\n") { pony -> pony.accept(this) }
return "\n$poniesString\n"
}
override fun visitEarthPony(pony: EarthPony): String {
return """
earth pony
${pony.name()}
${pony.cutie()}
""".trimIndent()
}
override fun visitUnicorn(pony: Unicorn): String {
return """
unicorn
${pony.name()}
${pony.cutie()}
""".trimIndent()
}
override fun visitPegasus(pony: Pegasus): String {
return """
pegasus
${pony.name()}
${pony.cutie()}
""".trimIndent()
}
}
abstract class LittlePony(private val name: String, private val cutieMark: String) {
fun name() = name
fun cutie() = cutieMark
abstract fun accept(visitor: PonyVisitor) : String
}
class EarthPony(name: String, cutieMark: String) : LittlePony(name, cutieMark) {
override fun accept(visitor: PonyVisitor) = visitor.visitEarthPony(this)
}
class Unicorn(name: String, cutieMark: String) : LittlePony(name, cutieMark) {
override fun accept(visitor: PonyVisitor) = visitor.visitUnicorn(this)
}
class Pegasus(name: String, cutieMark: String) : LittlePony(name, cutieMark) {
override fun accept(visitor: PonyVisitor) = visitor.visitPegasus(this)
}
================================================
FILE: src/main/kotlin/design_patterns/Сhain Of Responsibilities.kt
================================================
package design_patterns
/**
*
* Chain of responsibility is a behavioral design pattern that allows requests to be sent sequentially
*
* through a chain of handlers
*
*/
enum class BlockFactor { ONE, TWO, THREE }
// I decided to give an analogy from the Minecraft game.
// In this game there are blocks that can be broken with a stone pickaxe, iron and diamond.
// For example: diamond may mine by iron and diamond pickaxes unlike cobblestone, which is mined by any pickaxe
abstract class Block(private val factor: BlockFactor) {
fun mayMine(factor: BlockFactor) = this.factor.ordinal <= factor.ordinal
}
// the blocks are from the game
class StoneBlock: Block(BlockFactor.ONE)
class DiamondBlock: Block(BlockFactor.TWO)
class ObsidianBlock: Block(BlockFactor.THREE)
abstract class Pickaxe(private val factor: BlockFactor) {
private var nextPickaxe: Pickaxe? = null
fun changeNextPickaxe(pickaxe: Pickaxe) {
nextPickaxe = pickaxe
}
// we mine the block, if it doesn't work, we take another pickaxe, if there is one, returns true if a pickaxe can mine
fun mine(block: Block): Boolean {
if (block.mayMine(factor)) return true
return nextPickaxe?.mine(block) ?: false
}
}
// the pickaxes are from the game
class StonePickaxe: Pickaxe(BlockFactor.ONE)
class IronPickaxe: Pickaxe(BlockFactor.TWO)
class DiamondPickaxe: Pickaxe(BlockFactor.THREE)
================================================
FILE: src/main/kotlin/other/BinaryDigitsCounter.kt
================================================
package other
/**
*
* This algorithm counts the number of ones and zeros in a binary string
*
* and implemented on a finite state machine
*
*/
class BinaryDigitsCounter {
data class Result(private val ones: Int = 0, private val zeros: Int = 0)
// represents two states
private enum class State {
ONE, ZERO
}
fun compute(binaryString: String): Result { // 1010010011
if (binaryString.isEmpty()) {
return Result()
}
// define initial state
var currentState = if (binaryString.first() == '1') State.ONE else State.ZERO
var onesCount = 0
var zerosCount = 0
binaryString.forEach { symbol ->
// we use 'when' statement to toggle the state
when (currentState) {
State.ONE -> {
if (symbol == '0') {
zerosCount++
// move to another state
currentState = State.ZERO
} else {
onesCount++
}
}
State.ZERO -> {
if (symbol == '1') {
onesCount++
// move to another state
currentState = State.ONE
} else {
zerosCount++
}
}
}
}
return Result(onesCount, zerosCount)
}
}
================================================
FILE: src/main/kotlin/other/EuclidAlgorithm.kt
================================================
package other
/**
*
* Euclid's algorithm for finding the greatest common divisor
*
*/
class EuclidAlgorithm {
fun computeByDivisionWithRemainder(number1: Int, number2: Int) : Int {
var copyNumber1 = number1
var copyNumber2 = number2
while (copyNumber1 != 0 && copyNumber2 != 0) {
if (copyNumber1 > copyNumber2) {
copyNumber1 %= copyNumber2
} else {
copyNumber2 %= copyNumber1
}
}
return copyNumber1 + copyNumber2
}
fun computeBySubtraction(number1: Int, number2: Int): Int {
var copyNumber1 = number1
var copyNumber2 = number2
while (copyNumber1 != copyNumber2) {
if (copyNumber1 > copyNumber2) {
copyNumber1 -= copyNumber2
} else {
copyNumber2 -= copyNumber1
}
}
return copyNumber1
}
}
================================================
FILE: src/main/kotlin/other/Factorial.kt
================================================
package other
/**
*
* Algorithm for finding the factorial of a positive number n
*
*/
class Factorial {
/**
* iterative method
* worst time: O(n)
* amount of memory: O(1)
*/
fun compute(number: Int) : Int {
if (number <= 1) {
return 1
}
var result = 1
for (i in 2..number) {
result *= i
}
return result
}
/**
* recursive method
* worst time: O(n)
* amount of memory: O(n) - stack for recursion
*/
fun computeRecursive(number: Int) : Int {
return if (number <= 1) {
1
} else {
number * computeRecursive(number - 1)
}
}
// read more: https://kotlinlang.org/docs/functions.html#tail-recursive-functions
tailrec fun computeRecursiveWithKotlinOptimization(number: Int, result: Int = 1) : Int =
if (number <= 1) result else computeRecursiveWithKotlinOptimization(number - 1, result * number)
}
================================================
FILE: src/main/kotlin/other/FactorialAdvanced.kt
================================================
package other
import java.math.BigInteger
/**
*
* This algorithm is taken from Google Guava library
*
*/
class FactorialAdvanced {
// precomputed factorials
private val factorials = longArrayOf(
1L,
1L,
1L * 2,
1L * 2 * 3,
1L * 2 * 3 * 4,
1L * 2 * 3 * 4 * 5,
1L * 2 * 3 * 4 * 5 * 6,
1L * 2 * 3 * 4 * 5 * 6 * 7,
1L * 2 * 3 * 4 * 5 * 6 * 7 * 8,
1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9,
1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10,
1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11,
1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12,
1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13,
1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14,
1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15,
1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16,
1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17,
1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17 * 18,
1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17 * 18 * 19,
1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17 * 18 * 19 * 20
)
fun compute(n: Int): BigInteger {
if (n <= 0) {
return BigInteger.ZERO
}
if (n < factorials.size) {
return BigInteger.valueOf(factorials[n])
}
// pre-allocate space for our list of intermediate BigIntegers.
val approxSize = divide(n * log2Celling(n), Long.SIZE_BITS)
val bigNumbers = ArrayList(approxSize)
// start from the pre-computed maximum long factorial.
val startingNumber = factorials.size
var number = factorials[startingNumber - 1]
// strip off 2s from this value.
var shift = number.countTrailingZeroBits()
number = number shr shift
// use floor(log2(num)) + 1 to prevent overflow of multiplication.
var numberBits = log2Floor(number) + 1
var bits = log2Floor(startingNumber.toLong()) + 1
// check for the next power of two boundary, to save us a CLZ operation.
var nextPowerOfTwo = 1 shl bits - 1
// iteratively multiply the longs as big as they can go.
for (num in startingNumber..n) {
// check to see if the floor(log2(num)) + 1 has changed.
if ((num and nextPowerOfTwo) != 0) {
nextPowerOfTwo = nextPowerOfTwo shl 1
bits++
}
// get rid of the 2s in num.
val tz = num.toLong().countTrailingZeroBits()
val normalizedNum = (num shr tz).toLong()
shift += tz
// adjust floor(log2(num)) + 1.
val normalizedBits = bits - tz
// if it won't fit in a long, then we store off the intermediate product.
if (normalizedBits + numberBits >= Long.SIZE_BITS) {
bigNumbers.add(BigInteger.valueOf(number))
number = 1
numberBits = 0
}
number *= normalizedNum
numberBits = log2Floor(number) + 1
}
// check for leftovers.
if (number > 1) {
bigNumbers.add(BigInteger.valueOf(number))
}
// efficiently multiply all the intermediate products together.
return listNumbers(bigNumbers).shiftLeft(shift)
}
/**
* Returns the result of dividing p by q, rounding using the celling
*
* @throws ArithmeticException if q == 0
*/
private fun divide(number: Int, divider: Int): Int {
if (divider == 0) {
throw ArithmeticException("/ by zero") // for GWT
}
val div = number / divider
val rem = number - divider * div // equal to number % divider
if (rem == 0) {
return div
}
val signedNumber = 1 or (number xor divider shr Int.SIZE_BITS - 1)
val increment = signedNumber > 0
return if (increment) div + signedNumber else div
}
private fun listNumbers(numbers: List, start: Int = 0, end: Int = numbers.size): BigInteger {
return when (end - start) {
0 -> BigInteger.ONE
1 -> numbers[start]
2 -> numbers[start].multiply(numbers[start + 1])
3 -> numbers[start].multiply(numbers[start + 1]).multiply(numbers[start + 2])
else -> {
// otherwise, split the list in half and recursively do this.
val m = end + start ushr 1
listNumbers(numbers, start, m).multiply(listNumbers(numbers, m, end))
}
}
}
// returns the base-2 logarithm of number, rounded according to the celling.
private fun log2Celling(number: Int): Int {
return Int.SIZE_BITS - (number - 1).countLeadingZeroBits()
}
// returns the base-2 logarithm of number rounded according to the floor.
private fun log2Floor(number: Long): Int {
return Long.SIZE_BITS - 1 - number.countLeadingZeroBits()
}
}
================================================
FILE: src/main/kotlin/other/FactorialBigWithCache.kt
================================================
package other
import java.math.BigInteger
/**
*
* Algorithm for finding the factorial of a positive number n
*
* optimization: caching previous factorial values
*
* also adding large numbers
*
* worst time: O(n)
* the best time: O(1)
* amount of memory: O(n)
* problem: creating a huge number of BigInteger objects
*
*/
class FactorialBigWithCache {
private val cache = hashMapOf()
fun compute(number: Int) : BigInteger {
if (number <= 1) {
return BigInteger.ONE
}
val cachedResult = cache[number]
if (cachedResult != null) {
return cachedResult
}
var result = BigInteger.ONE
for (i in 2..number) {
result = result.multiply(i.toBigInteger())
cache[i] = result
}
return result
}
}
================================================
FILE: src/main/kotlin/other/FactorialWithCache.kt
================================================
package other
/**
*
* Algorithm for finding the factorial of a positive number n
*
* optimization: caching previous factorial values
*
* worst time: O(n)
* the best time: O(1)
* amount of memory: O(n)
*
*/
class FactorialWithCache {
private val cache = hashMapOf()
fun compute(number: Int) : Int {
if (number <= 1) {
return 1
}
val cachedResult = cache[number]
if (cachedResult != null) {
return cachedResult
}
var result = 1
for (i in 2..number) {
result *= i
cache[i] = result
}
return result
}
}
================================================
FILE: src/main/kotlin/other/FizzBuzz.kt
================================================
package other
/**
* The simplest FizzBuzz game
*
* description: the player says numbers in sequence, provided:
* - if the number is divisible by 3 it says fizz
* - if the number is divisible by 5 it says buzz
* - if the number is divisible by both 3 and 5, it says FizzBuzz
* - otherwise, the player calls the number itself
*/
class FizzBuzz {
// determines what to say for a number in the FizzBuzz game and returns Fizz, Buzz, FizzBuzz or number
fun compute(number: Int) : String {
return when {
number % 3 == 0 && number % 5 == 0 -> "FizzBuzz"
number % 3 == 0 -> "Fizz"
number % 5 == 0 -> "Buzz"
else -> number.toString()
}
}
}
================================================
FILE: src/main/kotlin/other/KnuthMorrisPrattAlgorithm.kt
================================================
package other
/**
*
* Knut Morris Pratt's Algorithm for finding a substring in a string
*
*/
class KnuthMorrisPrattAlgorithm {
// returns true if the substring is in the string
fun contains(sub: String, str: String) : Boolean {
val summary = "$sub$SEPARATOR$str"
val prefixFunctionValue = prefixFunction(summary)
return prefixFunctionValue.any { value -> value == sub.length }
}
// returns the number of occurrences of a substring in a string
fun count(sub: String, str: String) : Int {
val summary = "$sub$SEPARATOR$str"
return prefixFunction(summary).count { value -> value == sub.length }
}
// returns an array of prefix functions for a string
private fun prefixFunction(str: String) : Array {
val prefixFunctionsValues = Array(str.length) { 0 }
for (index in 1 until str.length) {
var prefixFunctionValue = prefixFunctionsValues[index - 1]
while (prefixFunctionValue > 0 && str[index] != str[prefixFunctionValue]) {
prefixFunctionValue = prefixFunctionsValues[prefixFunctionValue - 1]
}
if (str[index] == str[prefixFunctionValue]) {
prefixFunctionValue++
}
prefixFunctionsValues[index] = prefixFunctionValue
}
return prefixFunctionsValues
}
companion object {
// delimiter must not occur in source strings
private const val SEPARATOR = "#"
}
}
================================================
FILE: src/main/kotlin/other/LevenshteinLengthAlgorithm.kt
================================================
package other
import java.lang.Integer.min
/**
*
* Algorithm for determining the Levenshtein distance
*
*/
class LevenshteinLengthAlgorithm {
fun compute(str1: String, str2: String) : Int {
val matrix = Array(str1.length + 1) {
Array(str2.length + 1) { 0 }
}
for (i in 0..str1.length) {
matrix[i][0] = i
}
for (i in 0..str2.length) {
matrix[0][i] = i
}
for (i in 1..str1.length) {
for (j in 1..str2.length) {
if (str1[i - 1] == str2[j - 1]) {
matrix[i][j] = matrix[i - 1][j - 1]
} else {
matrix[i][j] = min(min(matrix[i - 1][j], matrix[i][j - 1]), matrix[i - 1][j - 1]) + 1
}
}
}
return matrix[str1.length][str2.length]
}
}
================================================
FILE: src/main/kotlin/other/MaxAlgorithm.kt
================================================
package other
import java.lang.IllegalArgumentException
/**
*
* Algorithm for finding the maximum value from a list
*
*/
class MaxAlgorithm {
fun > compute(items: List) : T {
if (items.isEmpty()) {
throw IllegalArgumentException("items list is empty!")
}
var max = items[0]
for (i in 1 until items.size) {
if (max < items[i]) {
max = items[i]
}
}
return max
}
/**
* returns the maximum element from the list recursively
*/
fun > computeRecursive(items: List) : T {
if (items.isEmpty()) {
throw IllegalArgumentException("items list is empty!")
}
if (items.size == 1) {
return items.first()
}
val first = items.first()
val others = items.subList(1, items.size)
val max = computeRecursive(others)
return if (first > max) first else max
}
}
================================================
FILE: src/main/kotlin/other/MinAlgorithm.kt
================================================
package other
import java.lang.IllegalArgumentException
/**
*
* Algorithm for finding the minimum value from a list
*
*/
class MinAlgorithm {
fun > compute(items: List) : T {
if (items.isEmpty()) {
throw IllegalArgumentException("items list is empty!")
}
var min = items[0]
for (i in 1 until items.size) {
if (min > items[i]) {
min = items[i]
}
}
return min
}
fun > computeRecursive(items: List) : T {
if (items.isEmpty()) {
throw IllegalArgumentException("items list is empty!")
}
if (items.size == 1) {
return items.first()
}
val first = items.first()
val others = items.subList(1, items.size)
val min = computeRecursive(others)
return if (first < min) first else min
}
}
================================================
FILE: src/main/kotlin/other/PalindromeAlgorithm.kt
================================================
package other
/**
*
* Algorithm for checking a string for a palindrome
*
* P.S. A palindrome is a word, number, phrase, or other sequence of symbols
* that reads the same backwards as forwards, such as "madam"
*/
class PalindromeAlgorithm {
// checks a string for a palindrome and returns true if the string is a palindrome
fun isPalindrome(text: String): Boolean {
if (text.length <= 1) {
return true
}
val length = text.length
for (index in 0 until length / 2) {
if (text[index] != text[length - index - 1]) {
return false
}
}
return true
}
fun isPalindromeSimplifiedVersion(text: String): Boolean {
return text == text.reversed()
}
}
================================================
FILE: src/main/kotlin/other/ParenthesisCheckAlgorithm.kt
================================================
package other
/**
*
* Algorithm for checking a string for correct placement of parentheses using stack
*
* ([]) - correctly
* ()(){} - correctly
* (() - incorrectly
* (())[][]}{ - incorrectly
*
*/
class ParenthesisCheckAlgorithm {
fun check(code: String = DEFAULT_CODE): Boolean {
// we use a regular kotlin list to create a stack
val stack = mutableListOf()
var index = 0
while (index < code.length) {
when (val symbol = code[index]) {
'(', '{', '[' -> stack.add(symbol)
')', '}', ']' -> {
val value = bracketRelations[stack.removeLastOrNull()]
if (symbol != value) {
return false
}
}
}
index++
}
return stack.isEmpty()
}
companion object {
// the correct C program
private const val DEFAULT_CODE = """
void main() {
printf("Hello, World!");
}
"""
private val bracketRelations = mapOf('(' to ')', '{' to '}', '[' to ']')
}
}
================================================
FILE: src/main/kotlin/other/ReverseArrayAlgorithm.kt
================================================
package other
/**
*
* Algorithm for reversing the order of an array
*
* complexity: O(n/2) + O(n)
*
*/
class ReverseArrayAlgorithm {
fun compute(array: Array) {
val size = array.size
for (index in 0 until size / 2) {
array[index] = array[size - index - 1].apply {
array[size - index - 1] = array[index]
}
}
}
}
================================================
FILE: src/main/kotlin/other/SieveOfEratosthenesAlgorithm.kt
================================================
package other
/**
*
* The sieve of Eratosthenes allows you to efficiently calculate a series of prime numbers
*
* algorithm complexity: nlog(logn) operations
*
*/
class SieveOfEratosthenesAlgorithm {
// computes a series of primes up to the maximum value and returns a list of prime numbers
fun compute(maxNumber: Int) : List {
val numbers = Array(maxNumber + 1) { index -> index >= 2 }
var x = 2
while (x * x <= maxNumber) {
if (numbers[x]) {
for (y in x * x..maxNumber step x) {
numbers[y] = false
}
}
x++
}
val primes = mutableListOf()
numbers.forEachIndexed { number, isPrime ->
if (isPrime) {
primes.add(number)
}
}
return primes
}
}
================================================
FILE: src/main/kotlin/other/Sqrt.kt
================================================
package other
/**
*
* Algorithm for finding the square root of a number
*
* read the wikipedia article: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Heron's_method
*
*/
class Sqrt {
// calculates the root of a number and returns result
fun compute(number: Double) : Double {
var value = number / 2
// the number of loop iterations is selected depending on the required accuracy
for (i in 1..100) {
value = (value + number / value) / 2
}
return value
}
}
================================================
FILE: src/main/kotlin/other/StringEqualsHashAlgorithm.kt
================================================
package other
/**
*
* Algorithm for comparing two strings with a hash
*
*/
class StringEqualsHashAlgorithm {
fun equals(source: String, pattern: String) : Boolean =
if (source.length != pattern.length) false else source.hash() == pattern.hash()
/**
*
* computes the hash of a string according to the formula:
*
* hash(abc) = a.code * primeCoefficient⁰ + b.code * primeCoefficient¹ + c.code * primeCoefficient²
*
*/
private fun String.hash() : Int {
var result = 0
var factor = 1
forEach { symbol ->
result += symbol.code * factor
factor *= PRIME_COEFFICIENT
}
// the hash can exceed the maximum Int value, so we limit it
return result.mod(Int.MAX_VALUE)
}
companion object {
/**
*
* I chose the nearest prime number for the size of the alphabet
*
* my alphabet is [a-z] [A-Z] ! , .
*
* size of the alphabet = 26 + 26 + 3 = 55 (is not prime)
*
*/
private const val PRIME_COEFFICIENT = 53
}
}
================================================
FILE: src/main/kotlin/other/SwapAlgorithm.kt
================================================
package other
/**
*
* Algorithm for exchanging two variables without a third additional
*
*/
class SwapAlgorithm {
// swaps two list values at the specified indexes
fun swap(list: MutableList, oldIndex: Int, newIndex: Int) {
if (oldIndex in list.indices && newIndex in list.indices) {
list[oldIndex] = list[oldIndex] + list[newIndex]
list[newIndex] = list[oldIndex] - list[newIndex]
list[oldIndex] = list[oldIndex] - list[newIndex]
}
}
// swaps two array values at the specified indexes
fun swap(array: Array, oldIndex: Int, newIndex: Int) {
if (oldIndex in array.indices && newIndex in array.indices) {
array[oldIndex] = array[oldIndex] + array[newIndex]
array[newIndex] = array[oldIndex] - array[newIndex]
array[oldIndex] = array[oldIndex] - array[newIndex]
}
}
// swaps two list values using Kotlin language features
fun swapKotlin(list: MutableList, oldIndex: Int, newIndex: Int) {
if (oldIndex in list.indices && newIndex in list.indices) {
list[oldIndex] = list[newIndex].apply {
list[newIndex] = list[oldIndex]
}
}
}
// swaps two array values using Kotlin language features
fun swapKotlin(array: Array, oldIndex: Int, newIndex: Int) {
if (oldIndex in array.indices && newIndex in array.indices) {
array[oldIndex] = array[newIndex].apply {
array[newIndex] = array[oldIndex]
}
}
}
}
================================================
FILE: src/main/kotlin/search/BinarySearch.kt
================================================
package search
/**
*
* Binary search algorithm only works for sorted lists and arrays
*
* best time: 1
* worst time: log(n)
* amount of memory: 1
*
*/
class BinarySearch {
// searches for an element in the array and returns the index of the searched element or -1
fun > search(array: Array, element: T) : Int {
if (array.isEmpty()) return -1
var left = 0
var right = array.size
while (left < right) {
val middle = left + (right - left) / 2
if (array[middle] < element) {
left = middle + 1
} else if (array[middle] > element) {
right = middle
} else {
return middle
}
}
return -1
}
// recursive method
// P.S. The tailrec modifier tells the compiler to optimize the recursion and turn it into an iterative version
tailrec fun > searchRecursive(array: Array, element: T, left: Int = 0, right: Int = array.size - 1): Int {
if (left <= right) {
val middle = left + (right - left) / 2
if (array[middle] == element) {
return middle
}
return if (array[middle] > element) {
searchRecursive(array, element, left, middle - 1)
} else {
searchRecursive(array, element, middle + 1, right)
}
}
return -1
}
// finds the left border index to insert an element into a sorted array
fun > leftBound(array: Array, element: T) : Int {
if (array.isEmpty()) return 0
var left = -1
var right = array.size
while ((right - left) > 1) {
val middle = left + (right - left) / 2
if (element > array[middle]) {
left = middle
} else {
right = middle
}
}
return left
}
// finds the right border index to insert an element into a sorted array
fun > rightBound(array: Array, element: T) : Int {
if (array.isEmpty()) return -1
var left = -1
var right = array.size
while ((right - left) > 1) {
val middle = (right + left) / 2
if (element > array[middle]) {
left = middle
} else {
right = middle
}
}
return right
}
}
================================================
FILE: src/main/kotlin/search/LinearSearch.kt
================================================
package search
/**
*
* Linear search algorithm
*
* best time: 1
* worst time: n
* amount of memory: 1
*
*/
class LinearSearch {
fun > search(array: Array, element: T) : Int {
var index = 0
while (index < array.size) {
if (element == array[index]) {
return index
}
index++
}
return -1
}
}
================================================
FILE: src/main/kotlin/sorting/BubbleSort.kt
================================================
package sorting
/**
*
* Bubble sort, sometimes referred to as sinking sort, is a simple sorting algorithm
*
* that repeatedly steps through the input list element by element, comparing the current element
*
* with the one after it, swapping their values if needed
*
*/
class BubbleSort {
/**
* worst time: n²
* best time: n²
* average time: n²
*
* amount of memory: 1
*/
fun > sort(array: Array) {
val arraySize = array.size
for (i in 0 until arraySize - 1) {
for (j in 0 until arraySize - 1 - i) {
if (array[j] > array[j + 1]) {
val tmp = array[j + 1]
array[j + 1] = array[j]
array[j] = tmp
}
}
}
}
/**
* worst time: n²
* best time: n
* average time: n²
*
* amount of memory: 1
*/
fun > sortImproved(array: Array) {
val arraySize = array.size
var isSorted = true
for (i in 0 until arraySize - 1) {
for (j in 0 until arraySize - 1 - i) {
if (array[j] > array[j + 1]) {
val tmp = array[j + 1]
array[j + 1] = array[j]
array[j] = tmp
isSorted = false
}
}
if (isSorted) break
}
}
}
================================================
FILE: src/main/kotlin/sorting/CountingSort.kt
================================================
package sorting
/**
*
* Counting sort is a sorting technique based on keys between a specific range
*
* worst time: n
* best time: n
* average time: n
*
* amount of memory: equals to the size of the range of numbers plus 1 (for example: 1001 for numbers from 0 to 1000)
*
* P.S. The use of counting sort is useful only when the sorted numbers have (or can be mapped to) a range of possible
* values that is small enough compared to the sorted set, for example, a million natural numbers less than 1000
*
*/
class CountingSort {
// sorts numbers in the range from start to end
fun sort(array: Array, start: Int, end: Int) {
val arraySize = array.size
val countedNumbers = Array(end + 1) { 0 }
var index = 0
while (index < arraySize) {
countedNumbers[array[index]]++
index++
}
index = 0
var currentNumber = start
while (currentNumber < countedNumbers.size) {
var frequency = countedNumbers[currentNumber]
while (frequency > 0) {
array[index++] = currentNumber
frequency--
}
currentNumber++
}
}
}
================================================
FILE: src/main/kotlin/sorting/InsertionSort.kt
================================================
package sorting
/**
*
* Insertion sort is a simple sorting algorithm that works similar to the way you sort playing cards in your hands.
*
* The array is virtually split into a sorted and an unsorted part.
*
* Values from the unsorted part are picked and placed at the correct position in the sorted part.
*
* worst time: n²
* best time: n
* average time: n²
*
* amount of time: 1
*
*/
class InsertionSort {
fun > sort(array: Array) {
val arraySize = array.size
for (i in 1 until arraySize) {
val current = array[i]
var j = i - 1
while (j >= 0 && array[j] > current) {
array[j + 1] = array[j]
j--
}
array[j + 1] = current
}
}
}
================================================
FILE: src/main/kotlin/sorting/MergeSort.kt
================================================
package sorting
/**
*
* Merge sort is a divide-and-conquer algorithm that was invented by John von Neumann in 1945
*
* Conceptually, a merge sort works as follows:
*
* 1) Divide the unsorted list into n sublists, each containing one element (a list of one element is considered sorted).
*
* 2) Repeatedly merge sublists to produce new sorted sublists until there is only one sublist remaining.
* This will be the sorted list.
*
*/
class MergeSort {
/**
* worst time: n * log(n)
* best time: n * log(n)
* average time: n * log(n)
*
* amount of memory: n
*/
fun > sort(array: Array) {
val arraySize = array.size
val temporaryArray = array.copyOf()
var windowSize = 1
while (windowSize < arraySize) {
var left = 0
while (left + windowSize < arraySize) {
val middle = left + windowSize
var right = middle + windowSize
if (right > arraySize) right = arraySize
var i = left
var k = left
var j = middle
while (i < middle && j < right) {
if (array[i] <= array[j]) {
temporaryArray[k] = array[i]
i++
} else {
temporaryArray[k] = array[j]
j++
}
k++
}
while (i < middle) {
temporaryArray[k] = array[i]
i++
k++
}
while (j < right) {
temporaryArray[k] = array[j]
j++
k++
}
i = left
while (i < right) {
array[i] = temporaryArray[i]
i++
}
left += windowSize * 2
}
windowSize *= 2
}
}
/**
* worst time: n * log(n)
* best time: n * log(n)
* average time: n * log(n)
*
* amount of memory: n * log(n)
*/
fun sortRecursive(array: Array) {
val arraySize = array.size
if (arraySize < 2)
return
val middle = arraySize / 2
val left = Array(middle) { 0 }
val right = Array(arraySize - middle) { 0 }
var i = 0
while (i < middle) {
left[i] = array[i]
i++
}
while (i < arraySize) {
right[i - middle] = array[i]
i++
}
sortRecursive(left)
sortRecursive(right)
val leftSize = left.size
val rightSize = right.size
i = 0
var j = 0
var k = 0
while (i < leftSize && j < rightSize) {
if (left[i] <= right[j]) {
array[k] = left[i]
i++
} else {
array[k] = right[j]
j++
}
k++
}
while (i < leftSize) {
array[k] = left[i]
i++
k++
}
while (j < rightSize) {
array[k] = right[j]
j++
k++
}
}
}
================================================
FILE: src/main/kotlin/sorting/QuickSort.kt
================================================
package sorting
import kotlin.random.Random
/**
*
* QuickSort is a sorting algorithm based on the Divide and Conquer algorithm
*
* that picks an element as a pivot and partitions the given array around the picked pivot
*
* by placing the pivot in its correct position in the sorted array.
*
*
* worst time: n²
* best time: n * log(n)
* average time: n * log(n)
*
* amount of memory: n
*
*/
class QuickSort {
fun > sort(array: Array, start: Int = 0, end: Int = array.size - 1) {
if (array.isEmpty()) return
if (start >= end) return
val pivotIndex = Random.nextInt(start, end + 1)
val pivot = array[pivotIndex]
var i = start
var j = end
while (i <= j) {
while (array[i] < pivot) {
i++
}
while (array[j] > pivot) {
j--
}
if (i <= j) {
val tmp = array[i]
array[i] = array[j]
array[j] = tmp
i++
j--
}
}
if (i < end) sort(array, i, end)
if (0 < j) sort(array, start, j)
}
}
================================================
FILE: src/main/kotlin/sorting/RadixSort.kt
================================================
package sorting
/**
*
* Radix Sort is a linear sorting algorithm that sorts elements by processing them digit by digit.
*
* It is an efficient sorting algorithm for integers or strings with fixed-size keys.
*
* worst time: * n
*
* amount of memory: 2 * n
*/
class RadixSort {
fun sort(array: Array) {
val arraySize = array.size
val arrayOfZeroBits = Array(arraySize) { 0 }
val arrayOfOneBits = Array(arraySize) { 0 }
val size = Int.SIZE_BITS
for (radix in 0 until size) {
var size1 = 0
var size2 = 0
for (index in array.indices) {
if (array[index].and(1 shl radix) == 0) {
arrayOfZeroBits[size1++] = array[index]
} else {
arrayOfOneBits[size2++] = array[index]
}
}
for (index in 0 until size1) {
array[index] = arrayOfZeroBits[index]
}
for (index in 0 until size2) {
array[size1 + index] = arrayOfOneBits[index]
}
}
}
}
================================================
FILE: src/main/kotlin/sorting/SelectionSort.kt
================================================
package sorting
/**
*
* Selection sort is a simple and efficient sorting algorithm that works by repeatedly selecting
*
* the smallest (or largest) element from the unsorted portion of the list and
*
* moving it to the sorted portion of the list.
*
* worst time: n²
* best time: n²
* average time: n²
*
* amount of memory: 1
*
*/
class SelectionSort {
fun > sort(array: Array) {
val arraySize = array.size
for (i in 0 until arraySize - 1) {
var min = i
for (j in i + 1 until arraySize) {
if (array[min] > array[j]) {
min = j
}
}
if (min != i) {
val tmp = array[i]
array[i] = array[min]
array[min] = tmp
}
}
}
}
================================================
FILE: src/main/kotlin/sorting/TimSort.kt
================================================
package sorting
import kotlin.math.min
/**
*
* Tim Sort is a hybrid sorting algorithm derived from merge sort and insertion sort
*
* used by Python’s sorted() and list.sort() functions, which was designed to perform well on
*
* many kinds of real-world data.
*
* worst time: n * log(n)
* best time: n
* average time: n * log(n)
*
* amount of memory: n
*
*/
class TimSort {
fun sort(array: Array) {
val arraySize = array.size
val minRunSize = minRunSize(arraySize)
var i = 0
while (i < arraySize) {
insertionSort(array, i, min(i + minRunSize - 1, arraySize - 1))
i += minRunSize
}
var mergingSize = minRunSize
while (mergingSize < arraySize) {
var start = 0
while (start < arraySize) {
val middle = start + mergingSize - 1
val end = min(start + 2 * mergingSize - 1, arraySize - 1)
if (middle < end) {
merge(array, start, middle, end)
}
start += mergingSize * 2
}
mergingSize *= 2
}
}
/**
* Minrun is chosen from the range 32 to 64 inclusive, such that the size of the data, divided by minrun, is equal to,
* or slightly less than, a power of two. The final algorithm takes the six most significant bits of the size of the array,
* adds one if any of the remaining bits are set, and uses that result as the minrun.
* This algorithm works for all arrays, including those smaller than 64; for arrays of size 63 or less,
* this sets minrun equal to the array size and Timsort reduces to an insertion sort
*/
private fun minRunSize(arraySize: Int) : Int {
var result = 0
var size = arraySize
while (size >= 64) {
result = result or (size and 1)
// shift one bit to the right until 6 significant bits remain
size = size shr 1
}
return size + result
}
private fun insertionSort(array: Array, start: Int, end: Int) {
var i = start + 1
while (i <= end) {
val current = array[i]
var j = i - 1
while (j >= start && array[j] > current) {
array[j + 1] = array[j]
j--
}
array[j + 1] = current
i++
}
}
private fun merge(array: Array, start: Int, middle: Int, end: Int) {
val leftSize = middle - start + 1
val rightSize = end - middle
var i = 0
val leftArray = Array(leftSize) { 0 }
while (i < leftSize) {
leftArray[i] = array[start + i]
i++
}
i = 0
val rightArray = Array(rightSize) { 0 }
while (i < rightSize) {
rightArray[i] = array[middle + i + 1]
i++
}
i = 0
var j = 0
var k = start
while (i < leftSize && j < rightSize) {
if (leftArray[i] <= rightArray[j]) {
array[k] = leftArray[i]
i++
} else {
array[k] = rightArray[j]
j++
}
k++
}
while (i < leftSize) {
array[k] = leftArray[i]
i++
k++
}
while (j < rightSize) {
array[k] = rightArray[j]
j++
k++
}
}
}
================================================
FILE: src/main/kotlin/structures/BinaryTree.kt
================================================
package structures
import java.util.LinkedList
/**
*
* Binary tree consists of nodes each of which has a maximum of two children.
*
* Child nodes satisfy the following requirements:
*
* - the left child is less than the parent
* - right child is larger than parent
*
* Hint: the worst time may be O(n) because the situation is possible when the elements follow each other 1,2,3,4...
* and the tree takes the following form:
*
* 1
* \
* 2
* \
* 3
* \
* 4
*
*/
class BinaryTree> {
private var root: Node? = null
val isEmpty: Boolean
get() = root == null
/**
* Complexity:
* worst time: O(n), read the hint in the description
* best time: O(log(n))
* average time: O(log(n))
*/
fun add(value: T) {
fun addRecursive(current: Node?, value: T): Node {
if (current == null) {
return Node(value)
}
if (value < current.value()) {
current.changeLeft(addRecursive(current.leftNode(), value))
} else if (value > current.value()) {
current.changeRight(addRecursive(current.rightNode(), value))
}
return current
}
root = addRecursive(root, value)
}
/**
* Complexity:
* worst time: O(n), read the hint in the description
* best time: O(1)
* average time: O(log(n))
*/
fun remove(value: T) {
fun smallestValue(root: Node): T {
val leftNode = root.leftNode()
if (leftNode === null) return root.value()
return smallestValue(leftNode)
}
fun removeRecursive(current: Node?, value: T): Node? {
if (current == null) {
return null
}
if (value == current.value()) {
if (current.leftNode() == null && current.rightNode() == null) {
return null
}
if (current.leftNode() == null) {
return current.rightNode()
}
if (current.rightNode() == null) {
return current.leftNode()
}
val smallestValue = smallestValue(current.rightNode()!!)
current.changeValue(smallestValue)
current.changeRight(removeRecursive(current.rightNode(), smallestValue))
return current
}
if (value < current.value()) {
current.changeLeft(removeRecursive(current.leftNode(), value))
} else {
current.changeRight(removeRecursive(current.rightNode(), value))
}
return current
}
root = removeRecursive(root, value)
}
/**
* Complexity:
* worst time: O(n), read the hint in the description
* best time: O(1)
* average time: O(log(n))
*/
fun contains(value: T): Boolean {
fun containsRecursive(current: Node?, value: T): Boolean {
if (current == null) {
return false
}
if (value == current.value()) {
return true
}
return if (value < current.value()) {
containsRecursive(current.leftNode(), value)
} else {
containsRecursive(current.rightNode(), value)
}
}
return containsRecursive(root, value)
}
/**
*
* Traversal of the binary tree in depth
*
* order: the left child, the parent, the right child
*
*/
fun traverseInOrder(): List {
fun traverseInOrderRecursive(node: Node?, nodes: MutableList) {
if (node != null) {
traverseInOrderRecursive(node.leftNode(), nodes)
nodes.add(node.value())
traverseInOrderRecursive(node.rightNode(), nodes)
}
}
val nodes = mutableListOf()
traverseInOrderRecursive(root, nodes)
return nodes
}
/**
*
* Traversal of the binary tree in depth
*
* order: the parent, the left child, the right child
*
*/
fun traversePreOrder(): List {
fun traversePreOrderRecursive(node: Node?, nodes: MutableList) {
if (node != null) {
nodes.add(node.value())
traversePreOrderRecursive(node.leftNode(), nodes)
traversePreOrderRecursive(node.rightNode(), nodes)
}
}
val nodes = mutableListOf()
traversePreOrderRecursive(root, nodes)
return nodes
}
/**
*
* Traversal of the binary tree in depth
*
* order: the left child, the right child, the parent
*
*/
fun traversePostOrder(): List {
fun traversePostOrderRec(node: Node?, nodes: MutableList) {
if (node != null) {
traversePostOrderRec(node.leftNode(), nodes)
traversePostOrderRec(node.rightNode(), nodes)
nodes.add(node.value())
}
}
val nodes = mutableListOf()
traversePostOrderRec(root, nodes)
return nodes
}
/**
*
* Traversal of the binary tree in breadth uses an additional data structure - a queue into which new tree
*
* nodes are added until the last node is added
*
*/
fun traverseLevelOrder(): List {
val current = root ?: return emptyList()
val queue = LinkedList>()
queue.add(current)
val nodeValues = mutableListOf()
while (queue.isNotEmpty()) {
val node = queue.removeFirst()
nodeValues.add(node.value())
val leftNode = node.leftNode()
if (leftNode != null) {
queue.add(leftNode)
}
val rightNode = node.rightNode()
if (rightNode != null) {
queue.add(rightNode)
}
}
return nodeValues
}
class Node(
private var value: T,
private var left: Node? = null,
private var right: Node? = null
) {
fun value() = value
fun changeValue(newValue: T) {
value = newValue
}
fun leftNode() = left
fun changeLeft(node: Node?) {
left = node
}
fun rightNode() = right
fun changeRight(node: Node?) {
right = node
}
}
}
================================================
FILE: src/main/kotlin/structures/CircularLinkedList.kt
================================================
package structures
/**
*
* LinkedList a data structure consisting of a collection of nodes that contain a link to the next/previous node.
*
* In the single LinkedList with circular reference each node contains a link to the next element,
* the last one refers to the first
*
*/
class CircularLinkedList {
private var head: Node? = null
private var tail: Node? = null
private var size: Int = 0
val isEmpty: Boolean
get() = head == null
/**
* The simple method to test functionality of the LinkedList with circular reference
*
* Complexity: O(n * cycleNumber)
*/
fun cyclingList(cycleNumber: Int = 1): List {
val nodeList = mutableListOf()
var currentCycle = 0
if (isEmpty) return nodeList
while (currentCycle < cycleNumber) {
var node = head
while (node != null) {
val nodeValue = node.value()
if (nodeValue != null) {
nodeList.add(nodeValue)
}
if (node === tail) {
currentCycle++
break
}
node = node.next()
}
}
return nodeList
}
/**
* Complexity:
* worst time: O(n)
* best time: O(1)
* average time: O(n)
*/
fun add(index: Int, value: T) : Boolean {
if (head == null) return false
var i = 0
var node = head
var prevNode = head
while (prevNode != null && node != null) {
if (i == index) {
val newNode = Node(value)
newNode.changeNext(node)
prevNode.changeNext(newNode)
size++
return true
}
i++
if (node === tail) {
break
}
prevNode = node
node = node.next()
}
return false
}
fun add(value: T) = addLast(value)
/**
* Complexity:
* worst time: O(1)
* best time: O(1)
* average time: O(1)
*/
fun addFirst(value: T) {
val node = Node(value)
if (head == null) {
head = node
tail = node
} else {
node.changeNext(head)
head = node
}
tail?.changeNext(head)
size++
}
/**
* Complexity:
* worst time: O(1)
* best time: O(1)
* average time: O(1)
*/
fun addLast(value: T) {
val node = Node(value)
if (head == null) {
head = node
tail = node
} else {
tail?.changeNext(node)
tail = node
}
tail?.changeNext(head)
size++
}
/**
* Complexity:
* worst time: O(n)
* best time: O(1)
* average time: O(n)
*/
fun contains(value: T) : Boolean {
if (head == null) return false
var node = head
while (node != null) {
if (node.value() == value) {
return true
}
if (node === tail) {
break
}
node = node.next()
}
return false
}
// Complexity: O(n)
fun clear() {
var node = head
while (node != null) {
val currentNode = node
node = node.next()
currentNode.changeNext(null)
currentNode.changeValue(null)
if (currentNode === tail) {
break
}
}
head = null
tail = null
size = 0
}
/**
* Complexity:
* worst time: O(n)
* best time: O(1)
* average time: O(n)
*/
fun remove(value: T) : Boolean {
if (head == null) return false
var previous: Node? = null
var node = head
while (node != null) {
if (node.value() == value) {
var nextNode = node.next()
if (nextNode === head) {
nextNode = null
}
previous?.changeNext(nextNode)
if (head === node) {
head = nextNode
}
if (tail === node) {
tail = previous
}
node.changeNext(null)
node.changeValue(null)
tail?.changeNext(head)
size--
return true
}
if (node === tail) {
break
}
previous = node
node = node.next()
}
return false
}
override fun toString(): String {
val builder = StringBuilder()
builder.append("size: $size\n")
builder.append("elements: ")
var node = head
while (node != null) {
builder.append(node.value())
// it's necessary to see the correct node connections
if (node.next() != null) {
builder.append(" - ")
}
if (node === tail) {
break
}
node = node.next()
}
return builder.toString()
}
class Node(
private var value: T? = null,
private var next: Node? = null
) {
fun next() = next
fun changeNext(node: Node? = null) {
next = node
}
fun value() = value
fun changeValue(newValue: T?) {
value = newValue
}
}
}
================================================
FILE: src/main/kotlin/structures/DoubleLinkedList.kt
================================================
package structures
/**
*
* LinkedList a data structure consisting of a collection of nodes that contain a link to the next/previous node.
*
* In the double LinkedList each node contains a link to the previous and next elements
*
*/
class DoubleLinkedList {
private var head: Node? = null
private var tail: Node? = null
private var size: Int = 0
val isEmpty: Boolean
get() = head == null
// Complexity: O(n)
val list: List
get() {
val nodes = mutableListOf()
var node = head
while (node != null) {
val nodeValue = node.value()
if (nodeValue != null) {
nodes.add(nodeValue)
}
node = node.next()
}
return nodes
}
// Complexity: O(n)
val reversedList: List
get() {
val nodes = mutableListOf()
var node = tail
while (node != null) {
val nodeValue = node.value()
if (nodeValue != null) {
nodes.add(nodeValue)
}
node = node.previous()
}
return nodes
}
/**
* Complexity:
* worst time: O(n)
* best time: O(1)
* average time: O(n)
*/
fun add(index: Int, value: T) : Boolean {
if (head == null) return false
var i = 0
var node = head
var prevNode = head
while (prevNode != null && node != null) {
if (i == index) {
val newNode = Node(value)
newNode.changeNext(node)
newNode.changePrevious(prevNode)
prevNode.changeNext(newNode)
size++
return true
}
i++
prevNode = node
node = node.next()
}
return false
}
fun add(value: T) = addLast(value)
/**
* Complexity:
* worst time: O(1)
* best time: O(1)
* average time: O(1)
*/
fun addFirst(value: T) {
val headNode = head
head = if (headNode == null) {
Node(value)
} else {
val newNode = Node(value = value, next = headNode)
headNode.changePrevious(newNode)
newNode
}
if (tail == null) {
tail = head
}
size++
}
/**
* Complexity:
* worst time: O(1)
* best time: O(1)
* average time: O(1)
*/
fun addLast(value: T) {
val tailNode = tail
tail = if (tailNode == null) {
Node(value)
} else {
val newNode = Node(value = value, previous = tailNode)
tailNode.changeNext(newNode)
newNode
}
if (head == null) {
head = tail
}
size++
}
/**
* Complexity:
* worst time: O(n)
* best time: O(1)
* average time: O(n)
*/
fun contains(value: T) : Boolean {
if (head == null) return false
var node = head
while (node != null) {
if (node.value() == value) {
return true
}
node = node.next()
}
return false
}
/**
* Complexity:
* worst time: O(n)
* best time: O(1)
* average time: O(n)
*/
fun remove(value: T) : Boolean {
if (head == null) return false
var previous: Node? = null
var node = head
while (node != null) {
if (node.value() == value) {
val nextNode = node.next()
previous?.changeNext(nextNode)
nextNode?.changePrevious(previous)
if (node === head) {
head = nextNode
}
if (node === tail) {
tail = previous
}
node.changePrevious(null)
node.changeNext(null)
node.changeValue(null)
size--
return true
}
previous = node
node = node.next()
}
return false
}
// Complexity: O(n)
fun clear() {
var node = head
while (node != null) {
val currentNode = node
node = node.next()
currentNode.changeNext(null)
currentNode.changePrevious(null)
currentNode.changeValue(null)
}
head = null
tail = null
size = 0
}
override fun toString(): String {
val builder = StringBuilder()
builder.append("size: $size\n")
builder.append("elements: ")
var node = head
while (node != null) {
// it's necessary to see the correct node connections
if (node.previous() != null) {
builder.append("- ")
}
builder.append(node.value())
// it's necessary to see the correct node connections
if (node.next() != null) {
builder.append(" -")
}
node = node.next()
}
return builder.toString()
}
class Node(
private var value: T? = null,
private var previous: Node? = null,
private var next: Node? = null
) {
fun next() = next
fun changeNext(node: Node? = null) {
next = node
}
fun previous() = previous
fun changePrevious(node: Node? = null) {
previous = node
}
fun value() = value
fun changeValue(newValue: T?) {
value = newValue
}
}
}
================================================
FILE: src/main/kotlin/structures/DynamicArray.kt
================================================
package structures
import java.lang.IllegalStateException
/**
*
* Dynamic array or array list is a random access, variable-size list data structure
*
* that allows elements to be added or removed, in Java this is java.util.ArrayList
*
* P.S. Kotlin lists use under the hood java.util.ArrayList on the JVM
*
* Example:
*
* 1) val numbers = listOf(1, 2, 3) // java.util.ArrayList
*
* 2) val symbols = mutableListOf('a', 'b', 'c') // also java.util.ArrayList
*
*/
class DynamicArray(private var capacity: Int = 10) {
private var data = arrayOfNulls(capacity)
private var size = 0
/**
* Complexity:
* worst time - O(n) because increaseSize() is called
* best time - O(1)
* average time - O(1)
*/
fun add(value: T) {
if (size <= data.size - 1) {
data[size] = value
} else {
increaseSize()
data[size] = value
}
size += 1
}
/**
* Complexity:
* worst time: O(n)
* best time: O(n)
* average time: O(n)
*/
fun remove(value: T) : Boolean {
var foundedIndex = -1
for (i in data.indices) {
if (data[i] == value) {
foundedIndex = i
break
}
}
if (foundedIndex == -1) return false
for (i in foundedIndex until data.size - 1) {
data[i] = data[i + 1]
}
size -= 1
return true
}
/**
* Complexity:
* worst time: O(n)
* best time: O(1)
* average time: O(n)
*/
fun contains(value: T): Boolean {
for (i in data.indices) {
if (data[i] == value) {
return true
}
}
return false
}
/**
* Complexity:
* worst time: O(1)
* best time: O(1)
* average time: O(1)
*/
fun set(index: Int, value: T): T? {
if (index !in 0 until size) throw IllegalStateException("The index $index is out of bounds!")
val oldValue = data[index]
data[index] = value
return oldValue as? T
}
/**
* Complexity:
* worst time: O(1)
* best time: O(1)
* average time: O(1)
*/
fun get(index: Int) : T {
if (index !in data.indices) throw IllegalStateException("The index $index is out of bounds!")
return data[index] as T
}
override fun toString(): String {
val builder = StringBuilder()
builder.append("capacity: $capacity\n")
builder.append("size: $size\n")
builder.append("elements: ")
for (i in 0 until size - 1) {
builder.append("${data[i]}, ")
}
builder.append(data[size - 1])
return builder.toString()
}
private fun increaseSize() {
capacity = (capacity * INCREASE_SIZE_COEFFICIENT).toInt()
val newArray = arrayOfNulls(capacity)
for (i in data.indices) {
newArray[i] = data[i]
}
data = newArray
}
companion object {
private const val INCREASE_SIZE_COEFFICIENT = 1.5f
}
}
================================================
FILE: src/main/kotlin/structures/Graph.kt
================================================
package structures
import java.util.LinkedList
import kotlin.collections.LinkedHashSet
/**
*
* Graph is a non-linear data structure consisting of vertices and edges.
*
* The vertices are sometimes also referred to as nodes and the edges are lines or arcs that connect any two nodes in the graph.
*
* More formally a Graph is composed of a set of vertices V and a set of edges E. The graph is denoted by G(E, V).
*
* Undirected graph is a type of graph where the edges have no specified direction assigned to the them.
*
*/
class Graph {
private val data = linkedMapOf, MutableList>>()
// Complexity: O(1)
fun addVertex(value: T) {
data.putIfAbsent(Vertex(value), mutableListOf())
}
// Complexity: O(n)
fun removeVertex(value: T) {
val removingVertex = Vertex(value)
data.values.forEach { list ->
list.remove(removingVertex)
}
data.remove(removingVertex)
}
// Complexity: O(1)
fun addEdge(value1: T, value2: T) {
val vertex1 = Vertex(value1)
val vertex2 = Vertex(value2)
data[vertex1]?.add(vertex2)
data[vertex2]?.add(vertex1)
}
// Complexity: O(1)
fun removeEdge(value1: T, value2: T) {
val vertex1 = Vertex(value1)
val vertex2 = Vertex(value2)
data[vertex1]?.remove(vertex2)
data[vertex2]?.remove(vertex1)
}
// returns the associated vertices with the given vertex value
fun connectedVertexes(value: T) = data[Vertex(value)]?.map { it.value } ?: emptyList()
/**
*
* Traversal of the graph in depth,
*
* returns all vertices of the graph
*
*/
fun depthFirstTraversal() : List {
val firstVertex = data.keys.firstOrNull() ?: return emptyList()
val visited = LinkedHashSet()
val queue = LinkedList>()
queue.push(firstVertex)
while (queue.isNotEmpty()) {
val vertex = queue.pollFirst()
if (!visited.contains(vertex.value)) {
visited.add(vertex.value)
queue.addAll(data[vertex] ?: emptyList())
}
}
return visited.toList()
}
/**
*
* Traversal of the graph in breadth,
*
* returns all vertices of the graph
*
*/
fun breadthFirstTraversal() : List {
val firstVertex = data.keys.firstOrNull() ?: return emptyList()
val visited = LinkedHashSet()
val queue = LinkedList>()
queue.add(firstVertex)
visited.add(firstVertex.value)
while (queue.isNotEmpty()) {
val vertex = queue.pollFirst()
data[vertex]?.forEach { connectedVertex ->
if (!visited.contains(connectedVertex.value)) {
visited.add(connectedVertex.value)
queue.add(connectedVertex)
}
}
}
return visited.toList()
}
private data class Vertex(val value: T)
}
================================================
FILE: src/main/kotlin/structures/GraphWithWeights.kt
================================================
package structures
/**
*
* Graph is a non-linear data structure consisting of vertices and edges.
*
* The vertices are sometimes also referred to as nodes and the edges are lines or arcs that connect any two nodes in the graph.
*
* More formally a Graph is composed of a set of vertices V and a set of edges E. The graph is denoted by G(E, V).
*
* Directed graph with weights is a type of graph where the edges have specified direction and weights assigned to the them.
*
*/
class GraphWithWeights {
private val data = linkedMapOf, MutableList>>()
// Complexity: O(1)
fun addVertex(value: T) {
data.putIfAbsent(Vertex(value), mutableListOf())
}
// Complexity: O(n)
fun removeVertex(value: T) {
val removingVertex = Vertex(value)
data.values.forEach { connections ->
connections.removeIf { it.vertex == removingVertex }
}
data.remove(removingVertex)
}
// Complexity: O(1)
fun addEdge(value1: T, value2: T, cost: Int) {
val vertex1 = Vertex(value1)
val vertex2 = Vertex(value2)
data[vertex1]?.add(VertexConnection(vertex2, cost))
}
// Complexity: O(n)
fun removeEdge(value1: T, value2: T) {
val vertex1 = Vertex(value1)
val vertex2 = Vertex(value2)
data[vertex1]?.removeIf { it.vertex == vertex2 }
}
// returns the associated vertices and their weights with the given vertex value
fun connectedVertexesWithWeights(value: T) = data[Vertex(value)]?.map { it.toString() } ?: emptyList()
/**
*
* Dijkstra's algorithm,
*
* returns pairs of a vertex and the minimum weight needed to get to that vertex,
*
* the starting vertex is the first added
*
*/
fun dijkstraAlgorithm(): Map {
if (data.isEmpty()) return emptyMap()
val unvisitedVertexes = linkedMapOf, Int>()
data.keys.forEach { vertex ->
unvisitedVertexes[vertex] = Int.MAX_VALUE
}
val visitedVertexes = linkedMapOf()
var minimumCost = 0
var currentVertex = unvisitedVertexes.keys.first()
while(unvisitedVertexes.isNotEmpty()) {
val neighbourVertexConnections = data[currentVertex] ?: emptyList()
for (neighbourVertexConnection in neighbourVertexConnections) {
val neighbourVertex = neighbourVertexConnection.vertex
if (!unvisitedVertexes.contains(neighbourVertex)) continue
val newCost = minimumCost + neighbourVertexConnection.cost
val neighbourVertexCost = unvisitedVertexes[neighbourVertex] ?: Int.MAX_VALUE
if (neighbourVertexCost > newCost) {
unvisitedVertexes[neighbourVertex] = newCost
}
}
visitedVertexes[currentVertex.value] = minimumCost
unvisitedVertexes.remove(currentVertex)
val nextUnvisitedEntry = unvisitedVertexes.entries
.filter { it.value != Int.MAX_VALUE }
.minByOrNull { it.value } ?: return visitedVertexes
currentVertex = nextUnvisitedEntry.key
minimumCost = nextUnvisitedEntry.value
}
return visitedVertexes
}
private data class Vertex(val value: T)
// helper class for defining graph weights
private data class VertexConnection(val vertex: Vertex, val cost: Int) {
override fun toString(): String = "vertex -> ${vertex.value}, cost -> $cost"
}
}
================================================
FILE: src/main/kotlin/structures/Matrix.kt
================================================
package structures
import java.lang.IllegalArgumentException
fun matrix(apply: Matrix.() -> Unit): Matrix {
val matrix = Matrix()
matrix.apply()
return matrix
}
/**
* Matrix is a rectangular table filled with numbers.
*
* For example:
* 1, 2, 3
* 4, 5, 6
* 7, 8, 9
*/
class Matrix() {
private val elements = mutableListOf()
private var columnCount = 0
private var rowCount = 0
private constructor(elements: List, columnCount: Int, rowCount: Int) : this() {
this.elements.addAll(elements)
this.columnCount = columnCount
this.rowCount = rowCount
}
fun row(vararg rowElements: Int) {
if (rowElements.isEmpty()) {
return
}
if (rowCount == 0) {
columnCount = rowElements.size
}
if (columnCount != rowElements.size) {
throw IllegalArgumentException("The number of elements in each row must be the same")
}
elements.addAll(rowElements.toTypedArray())
rowCount++
}
operator fun plus(value: Int): Matrix {
return Matrix(elements.map { it + value }, columnCount, rowCount)
}
operator fun plus(value: Matrix): Matrix {
if (rowCount != value.rowCount) throw IllegalArgumentException("The number of rows doesn't match")
if (columnCount != value.columnCount) throw IllegalArgumentException("The number of columns doesn't match")
return Matrix(elements.zip(value.elements) { element1, element2 -> element1 + element2 }, columnCount, rowCount)
}
operator fun minus(value: Int): Matrix {
return Matrix(elements.map { it - value }, columnCount, rowCount)
}
operator fun minus(value: Matrix): Matrix {
if (rowCount != value.rowCount) throw IllegalArgumentException("The number of rows doesn't match")
if (columnCount != value.columnCount) throw IllegalArgumentException("The number of columns doesn't match")
return Matrix(elements.zip(value.elements) { element1, element2 -> element1 - element2 }, columnCount, rowCount)
}
operator fun times(value: Int): Matrix {
return Matrix(elements.map { it * value }, columnCount, rowCount)
}
operator fun times(matrix: Matrix): Matrix {
val columnCountMatrix1 = columnCount
val rowCountMatrix1 = rowCount
val columnCountMatrix2 = matrix.columnCount
val rowCountMatrix2 = matrix.rowCount
if (columnCountMatrix1 != rowCountMatrix2) throw IllegalArgumentException("The number of columns of the first matrix doesn't match the number of rows of the second matrix")
val newElements = mutableListOf()
for (rowIndexMatrix1 in 0 until rowCountMatrix1) {
for (columnIndexMatrix2 in 0 until columnCountMatrix2) {
var sum = 0
for (sameSizeIndex in 0 until columnCountMatrix1) {
sum += elements[rowIndexMatrix1 * columnCountMatrix1 + sameSizeIndex] * matrix.elements[sameSizeIndex * columnCountMatrix2 + columnIndexMatrix2]
}
newElements.add(sum)
}
}
return Matrix(newElements, columnCountMatrix2, rowCountMatrix1)
}
operator fun div(value: Int): Matrix {
return Matrix(elements.map { it / value }, columnCount, rowCount)
}
override fun equals(other: Any?): Boolean {
if (other == null) return false
if (other !is Matrix) return false
if (this === other) return true
return columnCount == other.columnCount && rowCount == other.rowCount && elements == other.elements
}
override fun hashCode(): Int {
var result = elements.hashCode()
result = 31 * result + columnCount
result = 31 * result + rowCount
return result
}
override fun toString(): String {
val stringBuilder = StringBuilder("\n")
elements.forEachIndexed { index, value ->
val floating = if ((index + 1) % columnCount == 0) "" else ", "
stringBuilder.append("$value$floating")
if ((index + 1) % columnCount == 0) {
stringBuilder.append("\n")
}
}
return stringBuilder.toString()
}
}
================================================
FILE: src/main/kotlin/structures/MaxHeap.kt
================================================
package structures
import java.lang.IllegalArgumentException
/**
*
* Max-heap is a binary tree in which each parent is greater than its children
*
*/
class MaxHeap(private val maxSize: Int) {
private val data = IntArray(maxSize + 1) { Int.MIN_VALUE }
private val root = 1
private var size = 0
val isEmpty: Boolean
get() = size == 0
private val Int.parent
get() = this / 2
private val Int.leftChild
get() = this * 2
private val Int.rightChild
get() = this * 2 + 1
init {
if (maxSize <= 0) throw IllegalArgumentException("The heap must have maxSize larger than zero")
data[0] = Int.MAX_VALUE
}
// Complexity: O(logn)
fun add(element: Int) {
if (size >= maxSize) throw IllegalStateException("The heap is full!")
data[++size] = Int.MIN_VALUE
set(size, element)
}
// Complexity: O(logn)
fun set(index: Int, newValue: Int) {
if (index < root || index > maxSize) throw IllegalArgumentException("The heap doesn't have the such index: $index!")
if (newValue < data[index]) throw IllegalArgumentException("The new value $newValue is less than the previous: ${data[index]}")
data[index] = newValue
var current = index
while (current > root && data[current.parent] < data[current]) {
swap(current, current.parent)
current = current.parent
}
}
// Complexity: O(1)
fun peekMax() = data[root]
// Complexity: O(logn)
fun popMax(): Int {
if (size < 1) throw IllegalStateException("The heap is empty!")
val max = data[root]
data[root] = data[size--]
heapify(root)
return max
}
private tailrec fun heapify(pos: Int) {
val leftChild = pos.leftChild
val rightChild = pos.rightChild
var largest = pos
if (leftChild <= size && data[leftChild] > data[largest]) {
largest = leftChild
}
if (rightChild <= size && data[rightChild] > data[largest]) {
largest = rightChild
}
if (largest != pos) {
swap(pos, largest)
heapify(largest)
}
}
private fun swap(index1: Int, index2: Int) {
val tmp = data[index1]
data[index1] = data[index2]
data[index2] = tmp
}
companion object {
fun create(intArray: IntArray): MaxHeap {
val arraySize = intArray.size
val heap = MaxHeap(arraySize)
heap.size = intArray.size
var index = 0
while (index < arraySize) {
heap.data[index + 1] = intArray[index]
index++
}
var pos = arraySize / 2
while (pos >= 0) {
heap.heapify(pos)
pos--
}
return heap
}
}
}
================================================
FILE: src/main/kotlin/structures/MinHeap.kt
================================================
package structures
import java.lang.IllegalArgumentException
/**
*
* Min-heap is a binary tree in which each parent is smaller than its children
*
*/
class MinHeap(private val maxSize: Int) {
private val data = IntArray(maxSize + 1) { Int.MAX_VALUE }
private val root = 1
private var size = 0
val isEmpty: Boolean
get() = size == 0
private val Int.parent
get() = this / 2
private val Int.leftChild
get() = this * 2
private val Int.rightChild
get() = this * 2 + 1
init {
if (maxSize <= 0) throw IllegalArgumentException("The heap must have maxSize larger than zero")
data[0] = Int.MIN_VALUE
}
// Complexity: O(logn)
fun add(element: Int) {
if (size >= maxSize) throw IllegalStateException("The heap is full!")
data[++size] = Int.MAX_VALUE
set(size, element)
}
// Complexity: O(logn)
fun set(index: Int, newValue: Int) {
if (index < root || index > maxSize) throw IllegalArgumentException("The heap doesn't have the such index: $index!")
if (newValue > data[index]) throw IllegalArgumentException("The new value $newValue is more than the previous: ${data[index]}")
data[index] = newValue
var current = index
while (current > root && data[current.parent] > data[current]) {
swap(current, current.parent)
current = current.parent
}
}
// Complexity: O(1)
fun peekMin() = data[root]
// Complexity: O(logn)
fun popMin(): Int {
if (size < 1) throw IllegalStateException("The heap is empty!")
val max = data[root]
data[root] = data[size--]
heapify(root)
return max
}
private tailrec fun heapify(pos: Int) {
val leftChild = pos.leftChild
val rightChild = pos.rightChild
var minimum = pos
if (leftChild <= size && data[leftChild] < data[minimum]) {
minimum = leftChild
}
if (rightChild <= size && data[rightChild] < data[minimum]) {
minimum = rightChild
}
if (minimum != pos) {
swap(pos, minimum)
heapify(minimum)
}
}
private fun swap(index1: Int, index2: Int) {
val tmp = data[index1]
data[index1] = data[index2]
data[index2] = tmp
}
companion object {
fun create(intArray: IntArray): MinHeap {
val arraySize = intArray.size
val heap = MinHeap(arraySize)
heap.size = intArray.size
var index = 0
while (index < arraySize) {
heap.data[index + 1] = intArray[index]
index++
}
var pos = arraySize / 2
while (pos >= 0) {
heap.heapify(pos)
pos--
}
return heap
}
}
}
================================================
FILE: src/main/kotlin/structures/Queue.kt
================================================
package structures
import java.util.LinkedList
/**
*
* Queue is a data structure that follows the FIFO (first in, first out) principle
*
* LIFO implies that the element that is inserted first, comes out first
*
* The main operations:
*
* 1) enqueue - inserts an element at the end of the queue
* 2) dequeue - removes an element from the beginning of the queue
*
* All these operations performed in O(1) time.
*
*/
class Queue {
private val data = LinkedList()
val isEmpty: Boolean
get() = data.isEmpty()
val size: Int
get() = data.size
fun enqueue(item: T) {
data.add(item)
}
fun dequeue(): T {
if (isEmpty) throw IllegalStateException("The queue is empty")
// LinkedList under the hood stores a link to the first element
// this operation will be completed in time O(1)
return data.removeFirst()
}
fun peek(): T {
if (isEmpty) throw IllegalStateException("The queue is empty")
return data.first
}
fun clear() {
data.clear()
}
}
================================================
FILE: src/main/kotlin/structures/SingleLinkedList.kt
================================================
package structures
/**
*
* LinkedList a data structure consisting of a collection of nodes that contain a link to the next/previous node.
*
* In the single LinkedList each node contains a link only to the next element
*
*/
class SingleLinkedList() {
private var head: Node? = null
private var tail: Node? = null
private var size: Int = 0
val isEmpty: Boolean
get() = head == null
/**
* Complexity:
* worst time: O(n)
* best time: O(1)
* average time: O(n)
*/
fun add(index: Int, value: T) : Boolean {
if (head == null) return false
var i = 0
var node = head
var prevNode = head
while (prevNode != null && node != null) {
if (i == index) {
val newNode = Node(value)
newNode.changeNext(node)
prevNode.changeNext(newNode)
size++
return true
}
i++
prevNode = node
node = node.next()
}
return false
}
fun add(value: T) = addLast(value)
/**
* Complexity:
* worst time: O(1)
* best time: O(1)
* average time: O(1)
*/
fun addFirst(value: T) {
val node = Node(value)
if (head == null) {
head = node
tail = node
} else {
node.changeNext(head)
head = node
}
size++
}
/**
* Complexity:
* worst time: O(1)
* best time: O(1)
* average time: O(1)
*/
fun addLast(value: T) {
val node = Node(value)
if (head == null) {
head = node
tail = node
} else {
tail?.changeNext(node)
tail = node
}
size++
}
/**
* Complexity:
* worst time: O(n)
* best time: O(1)
* average time: O(n)
*/
fun contains(value: T) : Boolean {
if (head == null) return false
var node = head
while (node != null) {
if (node.value() == value) {
return true
}
node = node.next()
}
return false
}
/**
* Complexity:
* worst time: O(n)
* best time: O(1)
* average time: O(n)
*/
fun remove(value: T) : Boolean {
if (head == null) return false
var previous: Node? = null
var node = head
while (node != null) {
if (node.value() == value) {
val nextNode = node.next()
previous?.changeNext(nextNode)
if (head === node) {
head = nextNode
}
if (tail === node) {
tail = previous
}
node.changeNext(null)
node.changeValue(null)
size--
return true
}
previous = node
node = node.next()
}
return false
}
// Complexity: O(n)
fun clear() {
var node = head
while (node != null) {
val currentNode = node
node = node.next()
currentNode.changeNext(null)
currentNode.changeValue(null)
}
head = null
tail = null
size = 0
}
override fun toString(): String {
val builder = StringBuilder()
builder.append("size: $size\n")
builder.append("elements: ")
var node = head
while (node != null) {
builder.append(node.value())
// it's necessary to see the correct node connections
if (node.next() != null) {
builder.append(" - ")
}
node = node.next()
}
return builder.toString()
}
class Node(
private var value: T? = null,
private var next: Node? = null
) {
fun next() = next
fun changeNext(node: Node? = null) {
next = node
}
fun value() = value
fun changeValue(newValue: T?) {
value = newValue
}
}
}
================================================
FILE: src/main/kotlin/structures/Stack1.kt
================================================
package structures
import java.lang.IllegalArgumentException
import java.util.ArrayList
/**
*
* Stack is a linear data structure that follows the LIFO (last in first out) principle
*
* LIFO implies that the element that is inserted last, comes out first.
*
* The main operations:
*
* 1) push() - when we insert an element in a stack then the operation is known as a push
* 2) pop() - when we delete an element from the stack, the operation is known as a pop
*
* All these operations performed in O(1) time.
*
*/
class Stack1 {
// this implementation uses ArrayList
private val data = ArrayList()
val isEmpty: Boolean
get() = data.size == 0
val size: Int
get() = data.size
fun push(item: T) {
data.add(item)
}
fun pop() : T {
if (isEmpty) {
throw IllegalArgumentException("Stack is empty!")
}
return data.removeLast()
}
fun peek() : T {
if (isEmpty) {
throw IllegalArgumentException("Stack is empty!")
}
return data.last()
}
fun clear() {
data.clear()
}
}
================================================
FILE: src/main/kotlin/structures/Stack2.kt
================================================
package structures
import java.util.LinkedList
/**
*
* Stack is a linear data structure that follows the LIFO (Last-In-First-Out) principle
*
* LIFO implies that the element that is inserted last, comes out first.
*
* The main operations:
*
* push() - when we insert an element in a stack then the operation is known as a push.
* pop() - when we delete an element from the stack, the operation is known as a pop.
* If the stack is empty means that no element exists in the stack.
*
* All these operations performed in O(1) time.
*
*/
class Stack2 {
// this implementation uses LinkedList
private val data = LinkedList()
val isEmpty: Boolean
get() = data.size == 0
val size: Int
get() = data.size
fun push(item: T) {
data.add(item)
}
fun pop(): T {
if (isEmpty) {
throw IllegalArgumentException("Stack is empty!")
}
return data.removeLast()
}
fun peek(): T {
if (isEmpty) {
throw IllegalArgumentException("Stack is empty!")
}
return data.peekLast()
}
fun clear() {
data.clear()
}
}
================================================
FILE: src/test/kotlin/TestUtils.kt
================================================
import kotlin.random.Random
object TestUtils {
fun randomArray(size: Int) = List(size) { Random.nextInt(100) }.toTypedArray()
fun sortedArray(size: Int) = List(size) { it }.toTypedArray()
fun mutableRandomList(size: Int) = List(size) { Random.nextInt(100) }.toMutableList()
fun list(size: Int) = List(size) { it }
}
================================================
FILE: src/test/kotlin/design_patterns/AbstractFactoryTest.kt
================================================
package design_patterns
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsInstanceOf.instanceOf
import org.junit.Test
internal class AbstractFactoryTest {
@Test
fun test() {
val iosFactory = IOSButtonFactory()
val iosButton = iosFactory.createButton()
val iosText = iosFactory.createText()
assertThat(iosButton, instanceOf(IOSButton::class.java))
assertThat(iosText, instanceOf(IOSText::class.java))
val androidFactory = AndroidButtonFactory()
val androidButton = androidFactory.createButton()
val androidText = androidFactory.createText()
assertThat(androidButton, instanceOf(AndroidButton::class.java))
assertThat(androidText, instanceOf(AndroidText::class.java))
// we can draw iOS and Android components regardless of their implementation
listOf(iosButton, androidButton).forEach { it.draw() }
listOf(iosText, androidText).forEach { it.draw() }
}
}
================================================
FILE: src/test/kotlin/design_patterns/AdapterTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
internal class AdapterTest {
@Test
fun test() {
// we don't understand EnglishSpeaker interface
val englishSpeaker = EnglishSpeakerImpl()
// but we know about SpainSpeaker interface
val speakerAdapter = SpainSpeakerAdapter(englishSpeaker)
// EnglishSpeaker interface was changed to SpainSpeaker interface
val actual = speakerAdapter.speakSpanish()
assertEquals("Hola, amigo!", actual)
}
}
================================================
FILE: src/test/kotlin/design_patterns/BridgeTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
class BridgeTest {
@Test
fun test() {
val windowsSystem = WindowsSystem()
val macOSSystem = MacOSSystem()
// the line doesn't know how graphics are implemented in different operating systems
val line = GraphicLinePrimitive(0, 0, 100, 100)
line.draw(windowsSystem)
line.draw(macOSSystem)
// the circle doesn't know how graphics are implemented in different operating systems
val circle = GraphicCirclePrimitive(10, 10, 6)
circle.draw(windowsSystem)
circle.draw(macOSSystem)
assertEquals("""
Windows 10
Lines:
Windows graphic subsystem -> startX: 0, startY: 0, endX: 100, endY: 100
Circles:
Windows graphic subsystem -> centerX: 10, centerY: 10, radius: 6
""".trimIndent(), windowsSystem.toString())
assertEquals("""
MacOS 14
Lines:
MacOS graphic subsystem -> startX: 0, startY: 0, endX: 100, endY: 100
Circles:
MacOS graphic subsystem -> centerX: 10, centerY: 10, radius: 6
""".trimIndent(), macOSSystem.toString())
}
}
================================================
FILE: src/test/kotlin/design_patterns/BuilderTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
internal class BuilderTest {
@Test
fun test_first_variant() {
val dnsServerAddress = "8.8.8.8"
val callTimeout = 500
val connectTimeout = 3_000
val writeTimeout = 3_000
val readTimeout = 3_000
val httpClient = HttpConnectionClient1.Builder()
.dnsServerAddress(dnsServerAddress)
.callTimeout(callTimeout)
.connectTimeout(connectTimeout)
.writeTimeout(writeTimeout)
.readTimeout(readTimeout)
.build()
val expected = """
dns -> $dnsServerAddress
call timeout -> $callTimeout
connect timeout -> $connectTimeout
read timeout -> $readTimeout
write timeout -> $writeTimeout
""".trimIndent()
assertEquals(expected, httpClient.toString())
}
@Test
fun test_the_second_variant() {
val dnsServerAddress = "8.8.8.8"
val callTimeout = 500
val connectTimeout = 3_000
val writeTimeout = 3_000
val readTimeout = 3_000
val httpClient = HttpConnectionClient2.newBuilder()
.dnsServerAddress(dnsServerAddress)
.callTimeout(callTimeout)
.connectTimeout(connectTimeout)
.writeTimeout(writeTimeout)
.readTimeout(readTimeout)
.build()
val expected = """
dns -> $dnsServerAddress
call timeout -> $callTimeout
connect timeout -> $connectTimeout
read timeout -> $readTimeout
write timeout -> $writeTimeout
""".trimIndent()
assertEquals(expected, httpClient.toString())
}
@Test
fun test_third_variant() {
val dnsServerAddress = "8.8.8.8"
val callTimeout = 500
val connectTimeout = 3_000
val writeTimeout = 3_000
val readTimeout = 3_000
val httpClient = HttpConnectionClient3(
dnsServerAddress = dnsServerAddress,
callTimeout = callTimeout,
connectTimeout = connectTimeout,
readTimeout = readTimeout,
writeTimeout = writeTimeout
)
val expected = """
dns -> $dnsServerAddress
call timeout -> $callTimeout
connect timeout -> $connectTimeout
read timeout -> $readTimeout
write timeout -> $writeTimeout
""".trimIndent()
assertEquals(expected, httpClient.toString())
}
}
================================================
FILE: src/test/kotlin/design_patterns/ChainOfResponsibilitiesTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
class ChainOfResponsibilitiesTest {
@Test
fun test_when_we_have_only_stone_pickaxe() {
val pickaxe = StonePickaxe()
assertEquals(true, pickaxe.mine(StoneBlock()))
assertEquals(false, pickaxe.mine(DiamondBlock()))
assertEquals(false, pickaxe.mine(ObsidianBlock()))
}
@Test
fun test_when_we_have_stone_and_iron_pickaxes() {
val pickaxe = StonePickaxe()
pickaxe.changeNextPickaxe(IronPickaxe())
assertEquals(true, pickaxe.mine(StoneBlock()))
assertEquals(true, pickaxe.mine(DiamondBlock()))
assertEquals(false, pickaxe.mine(ObsidianBlock()))
}
@Test
fun test_when_we_have_all_three_pickaxes() {
val ironPickaxe = IronPickaxe()
ironPickaxe.changeNextPickaxe(DiamondPickaxe())
val stonePickaxe = StonePickaxe()
stonePickaxe.changeNextPickaxe(ironPickaxe)
assertEquals(true, stonePickaxe.mine(StoneBlock()))
assertEquals(true, stonePickaxe.mine(DiamondBlock()))
assertEquals(true, stonePickaxe.mine(ObsidianBlock()))
}
}
================================================
FILE: src/test/kotlin/design_patterns/CommandTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
internal class CommandTest {
@Test
fun `test usual commands`() {
val stereoSystem = StereoSystem()
val remoteControl = StereoSystemRemoteControl(mapOf(
"turnOn" to TurnOnCommand(stereoSystem),
"turnOff" to TurnOffCommand(stereoSystem),
"volume+" to IncreaseVolumeCommand(stereoSystem),
"volume-" to DecreaseVolumeCommand(stereoSystem)
))
remoteControl.pressButton("turnOn")
assertEquals("""
running status: true
volume value: 50
""".trimIndent(), stereoSystem.currentState)
remoteControl.pressButton("volume+")
remoteControl.pressButton("volume+")
remoteControl.pressButton("volume+")
assertEquals("""
running status: true
volume value: 80
""".trimIndent(), stereoSystem.currentState)
remoteControl.pressUndoButton()
remoteControl.pressUndoButton()
remoteControl.pressUndoButton()
remoteControl.pressUndoButton()
assertEquals("""
running status: false
volume value: 50
""".trimIndent(), stereoSystem.currentState)
}
@Test
fun `test macro command`() {
val stereoSystem = StereoSystem()
val remoteControl = StereoSystemRemoteControl(mapOf(
"party" to MacroCommand(
TurnOnCommand(stereoSystem),
IncreaseVolumeCommand(stereoSystem),
IncreaseVolumeCommand(stereoSystem),
IncreaseVolumeCommand(stereoSystem),
IncreaseVolumeCommand(stereoSystem),
IncreaseVolumeCommand(stereoSystem)
)
))
remoteControl.pressButton("party")
assertEquals("""
running status: true
volume value: 100
""".trimIndent(), stereoSystem.currentState)
remoteControl.pressUndoButton()
assertEquals("""
running status: false
volume value: 50
""".trimIndent(), stereoSystem.currentState)
}
}
================================================
FILE: src/test/kotlin/design_patterns/CompositeTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
class CompositeTest {
@Test
fun test() {
val menu = Menu("Delicious Restaurant")
val pizzasMenu = Menu("Pizzas")
pizzasMenu.addComponent(MenuItem("Cheese pizza", 10))
pizzasMenu.addComponent(MenuItem("Pepperoni pizza", 11))
menu.addComponent(pizzasMenu)
val cakesMenu = Menu("Cakes")
cakesMenu.addComponent(MenuItem("Chocolate cake", 13))
cakesMenu.addComponent(MenuItem("Cheese cake", 13))
menu.addComponent(cakesMenu)
assertEquals("""
Menu: Delicious Restaurant
Menu: Pizzas
title: Cheese pizza
price: 10
-------------
title: Pepperoni pizza
price: 11
-------------
Menu: Cakes
title: Chocolate cake
price: 13
-------------
title: Cheese cake
price: 13
-------------
""".trimIndent(), menu.fetchMenuInformation())
}
}
================================================
FILE: src/test/kotlin/design_patterns/DecoratorTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
class DecoratorTest {
@Test
fun test() {
val printer = ExclamationPrinter(
WorldPrinter(
SpacePrinter(
CommaPrinter(
HelloPrinter()
)
)
)
)
assertEquals("Hello, World!", printer.printedText())
}
}
================================================
FILE: src/test/kotlin/design_patterns/FacadeTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
internal class FacadeTest {
@Test
fun test() {
val goodsRepository = GoodsRepository(
GoodsDatabase(),
GoodsNetworkService(),
CategoryDatabase(),
CategoryNetworkService()
)
val actual = goodsRepository.goodsAndCategories()
assertEquals(
GoodsResult(
goods = listOf(GoodsEntity(
id = 1,
name = "Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software 2nd Edition",
description = "You know you don't want to reinvent the wheel, so you look to Design Patterns: the lessons learned by those who've faced the same software design problems.",
price = 41.94
)),
categories = listOf(CategoryEntity(
id = 1,
name = "Books"
))
),
actual
)
}
}
================================================
FILE: src/test/kotlin/design_patterns/FactoryMethodTest.kt
================================================
package design_patterns
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsInstanceOf.instanceOf
import org.junit.Assert.assertEquals
import org.junit.Test
class FactoryMethodTest {
@Test
fun `test WoodenHouseCompany`() {
val woodenHouseCompany = WoodenHouseCompany()
val house1 = woodenHouseCompany.orderHouse("77, Brook Ave", HouseCompany.HouseCompanyCost.CHEAP)
assertThat(house1, instanceOf(WoodenCheapHouse::class.java))
val house2 = woodenHouseCompany.orderHouse("77, Brook Ave", HouseCompany.HouseCompanyCost.AVERAGE)
assertThat(house2, instanceOf(WoodenAverageHouse::class.java))
val house3 = woodenHouseCompany.orderHouse("77, Brook Ave", HouseCompany.HouseCompanyCost.EXPENSIVE)
assertThat(house3, instanceOf(WoodenExpensiveHouse::class.java))
val expected = """
address = 77, Brook Ave
price = 50000
address = 77, Brook Ave
price = 250000
address = 77, Brook Ave
price = 1000000
""".trimIndent()
assertEquals(expected, woodenHouseCompany.examplesAlreadyBuiltHouses)
}
@Test
fun `test StoneHouseCompany`() {
val stoneHouseCompany = StoneHouseCompany()
val house1 = stoneHouseCompany.orderHouse("55, Brook Ave", HouseCompany.HouseCompanyCost.CHEAP)
assertThat(house1, instanceOf(StoneCheapHouse::class.java))
val house2 = stoneHouseCompany.orderHouse("55, Brook Ave", HouseCompany.HouseCompanyCost.AVERAGE)
assertThat(house2, instanceOf(StoneAverageHouse::class.java))
val house3 = stoneHouseCompany.orderHouse("55, Brook Ave", HouseCompany.HouseCompanyCost.EXPENSIVE)
assertThat(house3, instanceOf(StoneExpensiveHouse::class.java))
val expected = """
address = 55, Brook Ave
price = 45000
address = 55, Brook Ave
price = 230000
address = 55, Brook Ave
price = 900000
""".trimIndent()
assertEquals(expected, stoneHouseCompany.examplesAlreadyBuiltHouses)
}
}
================================================
FILE: src/test/kotlin/design_patterns/FlyweightTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
class FlyweightTest {
@Test
fun test() {
val garden = BeautifulGarden()
garden.placeTree("oak", "", 21, 10, 10)
garden.placeTree("birch", "", 15, 10, 20)
garden.placeTree("birch", "", 16, 10, 30)
garden.placeTree("birch", "", 17, 10, 40)
garden.placeTree("oak", "", 21, 20, 10)
garden.placeTree("oak", "", 21, 20, 20)
garden.placeTree("oak", "", 21, 20, 30)
garden.placeTree("birch", "", 15, 20, 40)
assertEquals("""
Beautiful Garden:
name: oak, height: 21, x: 10, y: 10
name: birch, height: 15, x: 10, y: 20
name: birch, height: 16, x: 10, y: 30
name: birch, height: 17, x: 10, y: 40
name: oak, height: 21, x: 20, y: 10
name: oak, height: 21, x: 20, y: 20
name: oak, height: 21, x: 20, y: 30
name: birch, height: 15, x: 20, y: 40
-|-|-|-|-|-|-|-|-|-|-
""".trimIndent(), garden.placedTreesAsString())
}
}
================================================
FILE: src/test/kotlin/design_patterns/InterpreterTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
class InterpreterTest {
@Test
fun test() {
// x = 10, y = 20, d = 5
// sum = x + y
// result = sum * d
val expression = PerformExpression(
SetIntVariableExpression("x", 10),
SetIntVariableExpression("y", 20),
AddVariablesExpression("x", "y", "sum"),
SetIntVariableExpression("d", 5),
MultipleVariablesExpression("sum", "d", "result")
)
val context = InterpreterContext()
expression.interpret(context)
assertEquals(150, context.fetchVariable("result"))
}
}
================================================
FILE: src/test/kotlin/design_patterns/IteratorTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
class IteratorTest {
@Test
fun test() {
val presents = arrayOf("chocolate cake", "snowboard", "snowman")
val giftBox = GiftBox(presents)
val giftBoxIterator = giftBox.iterator()
val actualPresents = mutableListOf()
while (giftBoxIterator.hasNext()) {
val present = giftBoxIterator.next()
actualPresents.add(present)
}
assertEquals(presents.toList(), actualPresents)
}
}
================================================
FILE: src/test/kotlin/design_patterns/MediatorTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
class MediatorTest {
@Test
fun test() {
val manager = SoftwareDevelopmentManager()
val customer = CustomerSoftwareDevelopmentMember(manager)
manager.changeCustomer(customer)
val designer = DesignerSoftwareDevelopmentMember(manager)
manager.changeDesigner(designer)
val programmer = ProgrammerSoftwareDevelopmentMember(manager)
manager.changeProgrammer(programmer)
val tester = TesterSoftwareDevelopmentMember(manager)
manager.changeTester(tester)
customer.finishWork()
designer.finishWork()
programmer.finishWork()
tester.finishWork()
assertEquals("""
Designer accepted the work: design development
Programmer accepted the work: writing code
Tester accepted the work: application testing
Customer accepted the work: business valuation
""".trimIndent(), manager.stagesAsString)
}
}
================================================
FILE: src/test/kotlin/design_patterns/MementoTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
class MementoTest {
@Test
fun test() {
// start Android system
val androidOS = AndroidSystem()
val greetingText = "Hello, World!"
val greetingView = TextView()
greetingView.setText(greetingText)
greetingView.draw()
// rotating Android device (recreating application components)
// Android system saves the states of running applications
androidOS.saveBundle(greetingView.onSaveInstanceState())
// the state of the text was lost, but we saved it
greetingView.setText("")
// Android device has already rotated
// The system restores the states of running applications
greetingView.onRestoreInstanceState(androidOS.restoreBundle())
assertEquals(greetingText, greetingView.text())
}
}
================================================
FILE: src/test/kotlin/design_patterns/ObserverTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
internal class ObserverTest {
@Test
fun test() {
val ponyList = PonyList()
val observer1 = PonyObserver { items ->
assertEquals(listOf("Twillight Sparkle"), items)
}
ponyList.addObserver(observer1)
// we add the first item, observer1 is triggered
ponyList.add("Twillight Sparkle")
// we remove observer1 so that it is not called again
ponyList.removeObserver(observer1)
val observer2 = PonyObserver { items ->
assertEquals(listOf("Twillight Sparkle", "Starlight Glimmer"), items)
}
ponyList.addObserver(observer2)
// we add the second item, observer2 is triggered
ponyList.add("Starlight Glimmer")
}
}
================================================
FILE: src/test/kotlin/design_patterns/PrototypeTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
class PrototypeTest {
@Test
fun test() {
// we have a list of sweets that need to be made at the confectionery factory
val recipesOfSweets = listOf(
OreoCookies("Original OREO", "Rich chocolate cookies with vanilla creme", 12),
OreoCookies("Golden OREO", "Sweet vanilla cookies with vanilla creme", 13),
OreoCookies("OREO Thins", "Sweet vanilla cookies with vanilla creme", 11),
`M&MsChocolate`("with puffed rice", 10),
`M&MsChocolate`("with peanuts", 11)
)
// we produce sweets according to existing recipes
val producedSweets = recipesOfSweets.flatMap { sweets -> List(10) { sweets.copy() } }
assertEquals(producedSweets.size, 50)
assertEquals(producedSweets[9], recipesOfSweets[0])
assertEquals(producedSweets[19], recipesOfSweets[1])
assertEquals(producedSweets[29], recipesOfSweets[2])
assertEquals(producedSweets[39], recipesOfSweets[3])
assertEquals(producedSweets[49], recipesOfSweets[4])
}
}
================================================
FILE: src/test/kotlin/design_patterns/ProxyTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
class ProxyTest {
@Test
fun test() {
// we use the proxy object instead of a real one
val mediaPlayer = AudioPlayerProxy()
mediaPlayer.play("track_0.mp3")
assertEquals("""
current audio: track_0.mp3
current status: RUNNING
""".trimIndent(), mediaPlayer.currentState)
mediaPlayer.pause()
assertEquals("""
current audio: track_0.mp3
current status: PAUSED
""".trimIndent(), mediaPlayer.currentState)
mediaPlayer.resume()
assertEquals("""
current audio: track_0.mp3
current status: RUNNING
""".trimIndent(), mediaPlayer.currentState)
mediaPlayer.stop()
assertEquals("""
current audio:
current status: NOT_INITIALIZED
""".trimIndent(), mediaPlayer.currentState)
}
}
================================================
FILE: src/test/kotlin/design_patterns/SingletonTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
internal class SingletonTest {
@Test
fun test() {
// we have one instance of SQLiteDatabase class
SQLiteDatabase.openConnection()
val actual = SQLiteDatabase.execSQL("select * from names")
val expected = listOf("Rick", "Morty", "Jerry", "Beth")
assertEquals(expected, actual)
SQLiteDatabase.closeConnection()
}
}
================================================
FILE: src/test/kotlin/design_patterns/StateTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
class StateTest {
@Test
fun test() {
val machine = CocaColaMachine()
assertEquals("NoDollarCocaColaState", machine.currentState)
machine.pressButton()
assertEquals("NoDollarCocaColaState", machine.currentState)
machine.insertDollar()
assertEquals("HaveDollarCocaColaState", machine.currentState)
machine.takeBackDollar()
assertEquals("NoDollarCocaColaState", machine.currentState)
machine.takeBackDollar()
assertEquals("NoDollarCocaColaState", machine.currentState)
machine.insertDollar()
assertEquals("HaveDollarCocaColaState", machine.currentState)
machine.pressButton()
assertEquals("NoDollarCocaColaState", machine.currentState)
machine.insertDollar()
assertEquals("HaveDollarCocaColaState", machine.currentState)
machine.pressButton()
assertEquals("NoDollarCocaColaState", machine.currentState)
machine.insertDollar()
assertEquals("HaveDollarCocaColaState", machine.currentState)
machine.pressButton()
assertEquals("EmptyCocaColaState", machine.currentState)
machine.insertDollar()
assertEquals("EmptyCocaColaState", machine.currentState)
machine.loadDrinks(1)
machine.insertDollar()
assertEquals("HaveDollarCocaColaState", machine.currentState)
machine.pressButton()
assertEquals("EmptyCocaColaState", machine.currentState)
}
}
================================================
FILE: src/test/kotlin/design_patterns/StrategyTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
internal class StrategyTest {
@Test
fun test() {
val strategy = OnlyChipsFilterStrategy()
val foodStore = FoodStore(strategy)
assertEquals(listOf(
FoodEntity(
"Lays Potato Chips Fried Crab Flavor",
2,
"chips"
),
FoodEntity(
"Lay's Potato Chips, Classic",
3,
"chips"
)
), foodStore.foodItems())
foodStore.changeStrategy(OnlyChocolateFilterStrategy())
assertEquals(listOf(
FoodEntity(
"Dove Chocolate",
3,
"chocolate"
),
FoodEntity(
"Ritter Sport Chocolate",
4,
"chocolate"
)
), foodStore.foodItems())
foodStore.changeStrategy(PriceFilterStrategy(3))
assertEquals(listOf(
FoodEntity(
"Lay's Potato Chips, Classic",
3,
"chips"
),
FoodEntity(
"Dove Chocolate",
3,
"chocolate"
),
FoodEntity(
"Ritter Sport Chocolate",
4,
"chocolate"
)
), foodStore.foodItems())
foodStore.changeStrategy(SearchWordFilterStrategy("Ritter Sport"))
assertEquals(listOf(
FoodEntity(
"Ritter Sport Chocolate",
4,
"chocolate"
)
), foodStore.foodItems())
}
}
================================================
FILE: src/test/kotlin/design_patterns/TemplateMethodTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
class TemplateMethodTest {
@Test
fun `test ChocolateCakeBaker`() {
val baker = ChocolateCakeBaker()
val actual = baker.makeCake(3)
val expected = Cake(
layers = listOf(
"chocolate cake layer",
"chocolate cake layer",
"chocolate cake layer"
),
cream = "chocolate cream",
sprinkles = "chocolate chips"
)
assertEquals(expected, actual)
}
@Test
fun `test WaffleCakeBaker`() {
val baker = WaffleCakeBaker()
val actual = baker.makeCake(3)
val expected = Cake(
layers = listOf(
"waffle cake layer",
"waffle cake layer",
"waffle cake layer"
),
cream = "custard cream",
sprinkles = "coconut flakes"
)
assertEquals(expected, actual)
}
}
================================================
FILE: src/test/kotlin/design_patterns/VisitorTest.kt
================================================
package design_patterns
import org.junit.Test
import org.junit.Assert.assertEquals
internal class VisitorTest {
private val expectedJson = """
[{
"what" : "unicorn",
"name" : "Twilight Sparkle",
"cutie_mark" : "star
},
{
"what" : "pegasus",
"name" : "Rainbow Dash",
"cutie_mark" : "lightning
},
{
"what" : "earth pony",
"name" : "Apple Jack",
"cutie_mark" : "apple
}]
""".trimIndent()
private val expectedXml = """
unicorn
Twilight Sparkle
star
pegasus
Rainbow Dash
lightning
earth pony
Apple Jack
apple
""".trimIndent()
@Test
fun test_json_visitor() {
val jsonVisitor = JsonVisitor()
val twilightSparkle = Unicorn("Twilight Sparkle", "star")
val rainbowDash = Pegasus("Rainbow Dash", "lightning")
val appleJack = EarthPony("Apple Jack", "apple")
val actual = jsonVisitor.visitPonies(twilightSparkle, rainbowDash, appleJack)
assertEquals(expectedJson, actual)
}
@Test
fun test_xml_visitor() {
val xmlVisitor = XmlVisitor()
val twilightSparkle = Unicorn("Twilight Sparkle", "star")
val rainbowDash = Pegasus("Rainbow Dash", "lightning")
val appleJack = EarthPony("Apple Jack", "apple")
val actual = xmlVisitor.visitPonies(twilightSparkle, rainbowDash, appleJack)
assertEquals(expectedXml, actual)
}
}
================================================
FILE: src/test/kotlin/other/BinaryDigitsCounterTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
internal class BinaryDigitsCounterTest {
private val counter = BinaryDigitsCounter()
@Test
fun test_empty_string() {
val result = counter.compute("")
assertEquals(BinaryDigitsCounter.Result(), result)
}
@Test
fun test_binary_string_1() {
val result = counter.compute("10101111000")
assertEquals(BinaryDigitsCounter.Result(6, 5), result)
}
@Test
fun test_binary_string_2() {
val result = counter.compute("0100000111110010101010")
assertEquals(BinaryDigitsCounter.Result(10, 12), result)
}
@Test
fun test_binary_string_3() {
val result = counter.compute("1111111111")
assertEquals(BinaryDigitsCounter.Result(10, 0), result)
}
@Test
fun test_binary_string_4() {
val result = counter.compute("0000000000")
assertEquals(BinaryDigitsCounter.Result(0, 10), result)
}
}
================================================
FILE: src/test/kotlin/other/EuclidAlgorithmTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
internal class EuclidAlgorithmTest {
private val euclidAlgorithm = EuclidAlgorithm()
@Test
fun `test computeByDivisionWithRemainder`() {
assertEquals(5, euclidAlgorithm.computeByDivisionWithRemainder(10, 5))
assertEquals(10, euclidAlgorithm.computeByDivisionWithRemainder(10, 100))
assertEquals(9, euclidAlgorithm.computeByDivisionWithRemainder(9, 27))
assertEquals(13, euclidAlgorithm.computeByDivisionWithRemainder(26, 39))
assertEquals(1, euclidAlgorithm.computeByDivisionWithRemainder(135, 13))
assertEquals(1, euclidAlgorithm.computeByDivisionWithRemainder(27, 19))
assertEquals(1, euclidAlgorithm.computeByDivisionWithRemainder(2, 17))
assertEquals(1, euclidAlgorithm.computeByDivisionWithRemainder(4, 9))
}
@Test
fun `test computeBySubtraction`() {
assertEquals(5, euclidAlgorithm.computeBySubtraction(10, 5))
assertEquals(10, euclidAlgorithm.computeBySubtraction(10, 100))
assertEquals(9, euclidAlgorithm.computeBySubtraction(9, 27))
assertEquals(13, euclidAlgorithm.computeBySubtraction(26, 39))
assertEquals(1, euclidAlgorithm.computeBySubtraction(135, 13))
assertEquals(1, euclidAlgorithm.computeBySubtraction(27, 19))
assertEquals(1, euclidAlgorithm.computeBySubtraction(2, 17))
assertEquals(1, euclidAlgorithm.computeBySubtraction(4, 9))
}
}
================================================
FILE: src/test/kotlin/other/FactorialAdvancedTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
internal class FactorialAdvancedTest {
private val factorial = FactorialAdvanced()
@Test
fun test_factorial_30() {
val actual = factorial.compute(30)
assertEquals("265252859812191058636308480000000", actual.toString())
}
@Test
fun test_factorial_60() {
val actual = factorial.compute(60)
assertEquals("8320987112741390144276341183223364380754172606361245952449277696409600000000000000", actual.toString())
}
@Test
fun test_factorial_90() {
val expected = "93326215443944152681699238856266700490715968264381621468592963" +
"895217599993229915608941463976156518286253697920827223758251185210916" +
"864000000000000000000000000"
val actual = factorial.compute(100)
assertEquals(expected, actual.toString())
}
@Test
fun test_factorial_200() {
val expected = "788657867364790503552363213932185062295135977687173263294742533244359449963403342920304" +
"2840119846239041772121389196388302576427902426371050619266249528299311134628572707633172373969" +
"8894392244562145166424025403329186413122742829485327752424240757390324032125740557956866022603" +
"1904170324062351700858796178922222789623703897374720000000000000000000000000000000000000000000000000"
val actual = factorial.compute(200)
assertEquals(expected, actual.toString())
}
@Test
fun test_factorial_1000() {
val expected = "40238726007709377354370243392300398571937486421071463254379991042993851" +
"2398629020592044208486969404800479988610197196058631666872994808558901323829669" +
"9445909974245040870737599188236277271887325197795059509952761208749754624970436" +
"0141827809464649629105639388743788648733711918104582578364784997701247663288983" +
"5955735432513185323958463075557409114262417474349347553428646576611667797396668" +
"8202912073791438537195882498081268678383745597317461360853795345242215865932019" +
"2809087829730843139284440328123155861103697680135730421616874760967587134831202" +
"5478589320767169132448426236131412508780208000261683151027341827977704784635868" +
"1701643650241536913982812648102130927612448963599287051149649754199093422215668" +
"3257208082133318611681155361583654698404670897560290095053761647584772842188967" +
"9646244945160765353408198901385442487984959953319101723355556602139450399736280" +
"7501378376153071277619268490343526252000158885351473316117021039681759215109077" +
"8801939317811419454525722386554146106289218796022383897147608850627686296714667" +
"4697562911234082439208160153780889893964518263243671616762179168909779911903754" +
"0312746222899880051954444142820121873617459926429565817466283029555702990243241" +
"5318161721046583203678690611726015878352075151628422554026517048330422614397428" +
"6933061690897968482590125458327168226458066526769958652682272807075781391858178" +
"8896522081643483448259932660433676601769996128318607883861502794659551311565520" +
"3609398818061213855860030143569452722420634463179746059468257310379008402443243" +
"8465657245014402821885252470935190620929023136493273497565513958720559654228749" +
"7740114133469627154228458623773875382304838656889764619273838149001407673104466" +
"4025989949022222176590433990188601856652648506179970235619389701786004081188972" +
"9918311021171229845901641921068884387121855646124960798722908519296819372388642" +
"6148396573822911231250241866493531439701374285319266498753372189406942814341185" +
"2015801412334482801505139969429015348307764456909907315243327828826986460278986" +
"4321139083506217095002597389863554277196742822248757586765752344220207573630569" +
"4988250879689281627538488633969099598262809561214509948717012445164612603790293" +
"0912088908694202851064018215439945715680594187274899809425474217358240106367740" +
"4595741785160829230135358081840096996372524230560855903700624271243416909004153" +
"6901059339838357779394109700277534720000000000000000000000000000000000000000000" +
"0000000000000000000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000000000000000000000000000000000000000000000000000" +
"000000000000000000000000000000000000000000000000"
val actual = factorial.compute(1000)
assertEquals(expected, actual.toString())
}
}
================================================
FILE: src/test/kotlin/other/FactorialBigWithCacheTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
internal class FactorialBigWithCacheTest {
private val factorial = FactorialBigWithCache()
@Test
fun test() {
assertEquals("30414093201713378043612608166064768844377641568960512000000000000", factorial.compute(50).toString())
assertEquals("265252859812191058636308480000000", factorial.compute(30).toString())
assertEquals("11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000", factorial.compute(70).toString())
}
}
================================================
FILE: src/test/kotlin/other/FactorialTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
internal class FactorialTest {
private val factorial = Factorial()
@Test
fun test_iterative() {
assertEquals(1, factorial.compute(0))
assertEquals(1, factorial.compute(1))
assertEquals(6, factorial.compute(3))
assertEquals(120, factorial.compute(5))
assertEquals(720, factorial.compute(6))
}
@Test
fun test_recursive() {
assertEquals(1, factorial.computeRecursive(0))
assertEquals(1, factorial.computeRecursive(1))
assertEquals(6, factorial.computeRecursive(3))
assertEquals(120, factorial.computeRecursive(5))
assertEquals(720, factorial.computeRecursive(6))
}
@Test
fun test_recursive_with_kotlin_optimization() {
assertEquals(1, factorial.computeRecursiveWithKotlinOptimization(0))
assertEquals(1, factorial.computeRecursiveWithKotlinOptimization(1))
assertEquals(6, factorial.computeRecursiveWithKotlinOptimization(3))
assertEquals(120, factorial.computeRecursiveWithKotlinOptimization(5))
assertEquals(720, factorial.computeRecursiveWithKotlinOptimization(6))
}
}
================================================
FILE: src/test/kotlin/other/FactorialWithCacheTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
internal class FactorialWithCacheTest {
private val factorial = FactorialWithCache()
@Test
fun test() {
assertEquals(6, factorial.compute(3))
assertEquals(120, factorial.compute(5))
assertEquals(720, factorial.compute(6))
assertEquals(3628800, factorial.compute(10))
}
}
================================================
FILE: src/test/kotlin/other/FizzBuzzTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
internal class FizzBuzzTest {
private val fizzBuzz = FizzBuzz()
@Test
fun test_fizz() {
val actual = fizzBuzz.compute(3)
val expected = "Fizz"
assertEquals(expected, actual)
}
@Test
fun test_buzz() {
val actual = fizzBuzz.compute(5)
val expected = "Buzz"
assertEquals(expected, actual)
}
@Test
fun test_fizz_buzz() {
val actual = fizzBuzz.compute(15)
val expected = "FizzBuzz"
assertEquals(expected, actual)
}
@Test
fun test_no_fizz_buzz() {
val actual = fizzBuzz.compute(1)
val expected = "1"
assertEquals(expected, actual)
}
}
================================================
FILE: src/test/kotlin/other/KnuthMorrisPrattAlgorithmTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
internal class KnuthMorrisPrattAlgorithmTest {
@Test
fun test() {
val knuthMorrisPrattAlgorithm = KnuthMorrisPrattAlgorithm()
val sentence1 = "Twillight Sparkle likes reading books!"
assertEquals(true, knuthMorrisPrattAlgorithm.contains("Twillight Sparkle", sentence1))
assertEquals(true, knuthMorrisPrattAlgorithm.contains("likes", sentence1))
assertEquals(true, knuthMorrisPrattAlgorithm.contains("reading", sentence1))
assertEquals(true, knuthMorrisPrattAlgorithm.contains("books", sentence1))
assertEquals(false, knuthMorrisPrattAlgorithm.contains("Apple Jack", sentence1))
assertEquals(false, knuthMorrisPrattAlgorithm.contains("loves", sentence1))
assertEquals(false, knuthMorrisPrattAlgorithm.contains("learning", sentence1))
assertEquals(false, knuthMorrisPrattAlgorithm.contains("articles", sentence1))
val sentence2 = """
Watch the Keynote, livestream replay, and tech talks to hear about the latest updates
in Android development directly from the Android team.
""".trimIndent()
assertEquals(3, knuthMorrisPrattAlgorithm.count("the", sentence2))
assertEquals(2, knuthMorrisPrattAlgorithm.count("Android", sentence2))
assertEquals(1, knuthMorrisPrattAlgorithm.count("and", sentence2))
assertEquals(1, knuthMorrisPrattAlgorithm.count("Keynote", sentence2))
assertEquals(0, knuthMorrisPrattAlgorithm.count("Kotlin", sentence2))
assertEquals(0, knuthMorrisPrattAlgorithm.count("Jetpack Compose", sentence2))
assertEquals(0, knuthMorrisPrattAlgorithm.count("Android Studio", sentence2))
assertEquals(0, knuthMorrisPrattAlgorithm.count("developers", sentence2))
}
}
================================================
FILE: src/test/kotlin/other/LevenshteinLengthAlgorithmTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
internal class LevenshteinLengthAlgorithmTest {
@Test
fun test() {
val levenshteinLengthAlgorithm = LevenshteinLengthAlgorithm()
val str1 = "hello"
val str2 = "hello,"
assertEquals(1, levenshteinLengthAlgorithm.compute(str1, str2))
val str3 = "hello, world!"
val str4 = "hello, friend"
assertEquals(6, levenshteinLengthAlgorithm.compute(str3, str4))
assertEquals(0, levenshteinLengthAlgorithm.compute(str1, str1))
assertEquals(0, levenshteinLengthAlgorithm.compute(str2, str2))
assertEquals(0, levenshteinLengthAlgorithm.compute(str3, str3))
assertEquals(0, levenshteinLengthAlgorithm.compute(str4, str4))
}
}
================================================
FILE: src/test/kotlin/other/MaxAlgorithmTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
internal class MaxAlgorithmTest {
private val maxAlgorithm = MaxAlgorithm()
@Test
fun `test iterative algorithm`() {
val actual1 = maxAlgorithm.compute(listOf(10, 9, 8, 7, 6, 5, 4, 3, 2, 1))
assertEquals(10, actual1)
val actual2 = maxAlgorithm.compute(listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
assertEquals(10, actual2)
val actual3 = maxAlgorithm.compute(listOf(-50, 10, 6, -100, -9, 110))
assertEquals(110, actual3)
}
@Test
fun `test recursive algorithm`() {
val actual1 = maxAlgorithm.computeRecursive(listOf(10, 9, 8, 7, 6, 5, 4, 3, 2, 1))
assertEquals(10, actual1)
val actual2 = maxAlgorithm.computeRecursive(listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
assertEquals(10, actual2)
val actual3 = maxAlgorithm.computeRecursive(listOf(-50, 10, 6, -100, -9, 110))
assertEquals(110, actual3)
}
}
================================================
FILE: src/test/kotlin/other/MinAlgorithmTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
internal class MinAlgorithmTest {
private val minAlgorithm = MinAlgorithm()
@Test
fun `test iterative algorithm`() {
val actual1 = minAlgorithm.compute(listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
assertEquals(1, actual1)
val actual2 = minAlgorithm.compute(listOf(10, 9, 8, 7, 6, 5, 4, 3, 2, 1))
assertEquals(1, actual2)
val actual3 = minAlgorithm.compute(listOf(-50, 10, 6, -100, -9, 110))
assertEquals(-100, actual3)
}
@Test
fun `test recursive algorithm`() {
val actual1 = minAlgorithm.computeRecursive(listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
assertEquals(1, actual1)
val actual2 = minAlgorithm.computeRecursive(listOf(10, 9, 8, 7, 6, 5, 4, 3, 2, 1))
assertEquals(1, actual2)
val actual3 = minAlgorithm.computeRecursive(listOf(-50, 10, 6, -100, -9, 110))
assertEquals(-100, actual3)
}
}
================================================
FILE: src/test/kotlin/other/PalindromeAlgorithmTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
class PalindromeAlgorithmTest {
private val palindromeAlgorithm = PalindromeAlgorithm()
@Test
fun `test empty string`() {
assertEquals(true, palindromeAlgorithm.isPalindrome(""))
assertEquals(true, palindromeAlgorithm.isPalindromeSimplifiedVersion(""))
}
@Test
fun `test string with one symbol`() {
assertEquals(true, palindromeAlgorithm.isPalindrome("a"))
assertEquals(true, palindromeAlgorithm.isPalindrome("b"))
assertEquals(true, palindromeAlgorithm.isPalindrome("c"))
assertEquals(true, palindromeAlgorithm.isPalindrome("d"))
assertEquals(true, palindromeAlgorithm.isPalindrome("e"))
assertEquals(true, palindromeAlgorithm.isPalindrome("f"))
assertEquals(true, palindromeAlgorithm.isPalindromeSimplifiedVersion("a"))
assertEquals(true, palindromeAlgorithm.isPalindromeSimplifiedVersion("b"))
assertEquals(true, palindromeAlgorithm.isPalindromeSimplifiedVersion("c"))
assertEquals(true, palindromeAlgorithm.isPalindromeSimplifiedVersion("d"))
assertEquals(true, palindromeAlgorithm.isPalindromeSimplifiedVersion("e"))
assertEquals(true, palindromeAlgorithm.isPalindromeSimplifiedVersion("f"))
}
@Test
fun `test string is palindrome`() {
assertEquals(true, palindromeAlgorithm.isPalindrome("tenet"))
assertEquals(true, palindromeAlgorithm.isPalindrome("madam"))
assertEquals(true, palindromeAlgorithm.isPalindrome("racecar"))
assertEquals(true, palindromeAlgorithm.isPalindrome("dad"))
assertEquals(true, palindromeAlgorithm.isPalindromeSimplifiedVersion("tenet"))
assertEquals(true, palindromeAlgorithm.isPalindromeSimplifiedVersion("madam"))
assertEquals(true, palindromeAlgorithm.isPalindromeSimplifiedVersion("racecar"))
assertEquals(true, palindromeAlgorithm.isPalindromeSimplifiedVersion("dad"))
}
@Test
fun `test string is not palindrome`() {
assertEquals(false, palindromeAlgorithm.isPalindrome("friend"))
assertEquals(false, palindromeAlgorithm.isPalindrome("success"))
assertEquals(false, palindromeAlgorithm.isPalindrome("mistake"))
assertEquals(false, palindromeAlgorithm.isPalindrome("language"))
assertEquals(false, palindromeAlgorithm.isPalindromeSimplifiedVersion("friend"))
assertEquals(false, palindromeAlgorithm.isPalindromeSimplifiedVersion("success"))
assertEquals(false, palindromeAlgorithm.isPalindromeSimplifiedVersion("mistake"))
assertEquals(false, palindromeAlgorithm.isPalindromeSimplifiedVersion("language"))
}
}
================================================
FILE: src/test/kotlin/other/ParenthesisCheckAlgorithmTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
internal class ParenthesisCheckAlgorithmTest {
private val parenthesisCheckAlgorithm = ParenthesisCheckAlgorithm()
@Test
fun `test success`() {
// the correct C program
assertEquals(true, parenthesisCheckAlgorithm.check("""
void main() {
printf("Hello, World!");
}
"""))
assertEquals(true, parenthesisCheckAlgorithm.check(""))
assertEquals(true, parenthesisCheckAlgorithm.check("()"))
assertEquals(true, parenthesisCheckAlgorithm.check("{}"))
assertEquals(true, parenthesisCheckAlgorithm.check("[]"))
assertEquals(true, parenthesisCheckAlgorithm.check("(([[]]))[[]]"))
assertEquals(true, parenthesisCheckAlgorithm.check("[[[[((()))]]]]{}{}{}"))
assertEquals(true, parenthesisCheckAlgorithm.check("(())()()[][]{{()}}{}"))
}
@Test
fun `test failed`() {
// the failed C program
assertEquals(false, parenthesisCheckAlgorithm.check("""
void main({
printf("Hello, World!";
}
"""))
assertEquals(false, parenthesisCheckAlgorithm.check("("))
assertEquals(false, parenthesisCheckAlgorithm.check(")"))
assertEquals(false, parenthesisCheckAlgorithm.check("{"))
assertEquals(false, parenthesisCheckAlgorithm.check("}"))
assertEquals(false, parenthesisCheckAlgorithm.check("["))
assertEquals(false, parenthesisCheckAlgorithm.check("]"))
assertEquals(false, parenthesisCheckAlgorithm.check("[](){{}"))
assertEquals(false, parenthesisCheckAlgorithm.check("[[[]]]{}{})"))
assertEquals(false, parenthesisCheckAlgorithm.check("{{{}}}({[}]))[]"))
}
}
================================================
FILE: src/test/kotlin/other/ReverseArrayAlgorithmTest.kt
================================================
package other
import org.junit.Test
import junit.framework.TestCase.assertEquals
internal class ReverseArrayAlgorithmTest {
private val reverseArrayAlgorithm = ReverseArrayAlgorithm()
@Test
fun `test numbers`() {
val array = arrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
reverseArrayAlgorithm.compute(array)
assertEquals(listOf(10, 9, 8, 7, 6, 5, 4, 3, 2, 1), array.toList())
}
@Test
fun `test strings`() {
val array = arrayOf("Twillight Sparkle", "Pinky Pie", "Apple Jack", "Rainbow Dash", "Fluttershy", "Rarity")
reverseArrayAlgorithm.compute(array)
assertEquals(listOf("Rarity", "Fluttershy", "Rainbow Dash", "Apple Jack", "Pinky Pie", "Twillight Sparkle"), array.toList())
}
}
================================================
FILE: src/test/kotlin/other/SieveOfEratosthenesAlgorithmTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
internal class SieveOfEratosthenesAlgorithmTest {
private val eratosthenesAlgorithm = SieveOfEratosthenesAlgorithm()
@Test
fun tes() {
assertEquals(emptyList(), eratosthenesAlgorithm.compute(1))
assertEquals(listOf(2, 3, 5, 7), eratosthenesAlgorithm.compute(10))
assertEquals(listOf(2, 3, 5, 7, 11, 13, 17, 19), eratosthenesAlgorithm.compute(20))
assertEquals(listOf(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37), eratosthenesAlgorithm.compute(40))
assertEquals(
listOf(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101),
eratosthenesAlgorithm.compute(102)
)
assertEquals(
listOf(
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293
),
eratosthenesAlgorithm.compute(300)
)
}
}
================================================
FILE: src/test/kotlin/other/SqrtTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
internal class SqrtTest {
@Test
fun test() {
val sqrt = Sqrt()
assertEquals(3.0, sqrt.compute(9.0), 0.0)
assertEquals(2.0, sqrt.compute(4.0), 0.0)
assertEquals(6.0, sqrt.compute(36.0), 0.0)
}
}
================================================
FILE: src/test/kotlin/other/StringEqualsHashAlgorithmTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
internal class StringEqualsHashAlgorithmTest {
private val stringEqualsHashAlgorithm = StringEqualsHashAlgorithm()
@Test
fun test_two_the_same_strings() {
val str1 = "Twilight Sparkle"
val str2 = "Twilight Sparkle"
assertEquals(true, stringEqualsHashAlgorithm.equals(str1, str2))
}
@Test
fun test_two_different_strings() {
val greeting = "How are you?"
val pattern = "Happy birthday to me!"
assertEquals(false, stringEqualsHashAlgorithm.equals(greeting, pattern))
}
}
================================================
FILE: src/test/kotlin/other/SwapAlgorithmTest.kt
================================================
package other
import org.junit.Test
import org.junit.Assert.assertEquals
internal class SwapAlgorithmTest {
private val swapAlgorithm = SwapAlgorithm()
@Test
fun test_list() {
val list = mutableListOf(1, 2, 3, 4, 5, 6)
swapAlgorithm.swap(list, 0, 5)
swapAlgorithm.swap(list, 1, 4)
swapAlgorithm.swap(list, 2, 3)
assertEquals(listOf(6, 5, 4, 3, 2, 1), list)
}
@Test
fun test_array() {
val array = arrayOf(1, 2, 3, 4, 5, 6)
swapAlgorithm.swap(array, 0, 5)
swapAlgorithm.swap(array, 1, 4)
swapAlgorithm.swap(array, 2, 3)
assertEquals(listOf(6, 5, 4, 3, 2, 1), array.toList())
}
@Test
fun test_list_kotlin() {
val list = mutableListOf(1, 2, 3, 4, 5, 6)
swapAlgorithm.swapKotlin(list, 0, 5)
swapAlgorithm.swapKotlin(list, 1, 4)
swapAlgorithm.swapKotlin(list, 2, 3)
assertEquals(listOf(6, 5, 4, 3, 2, 1), list)
}
@Test
fun test_array_kotlin() {
val array = arrayOf(1, 2, 3, 4, 5, 6)
swapAlgorithm.swapKotlin(array, 0, 5)
swapAlgorithm.swapKotlin(array, 1, 4)
swapAlgorithm.swapKotlin(array, 2, 3)
assertEquals(listOf(6, 5, 4, 3, 2, 1), array.toList())
}
}
================================================
FILE: src/test/kotlin/search/BinarySearchTest.kt
================================================
package search
import org.junit.Test
import org.junit.Assert.assertEquals
internal class BinarySearchTest {
private val searchAlgo = BinarySearch()
@Test
fun `test search`() {
val array = arrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
assertEquals(-1, searchAlgo.search(emptyArray(), 0))
assertEquals(-1, searchAlgo.search(array, 0))
assertEquals(-1, searchAlgo.search(array, 11))
assertEquals(0, searchAlgo.search(array, 1))
assertEquals(2, searchAlgo.search(array, 3))
assertEquals(4, searchAlgo.search(array, 5))
assertEquals(6, searchAlgo.search(array, 7))
assertEquals(8, searchAlgo.search(array, 9))
assertEquals(9, searchAlgo.search(array, 10))
assertEquals(-1, searchAlgo.searchRecursive(emptyArray(), 0))
assertEquals(-1, searchAlgo.searchRecursive(array, 0))
assertEquals(-1, searchAlgo.searchRecursive(array, 11))
assertEquals(0, searchAlgo.searchRecursive(array, 1))
assertEquals(2, searchAlgo.searchRecursive(array, 3))
assertEquals(4, searchAlgo.searchRecursive(array, 5))
assertEquals(6, searchAlgo.searchRecursive(array, 7))
assertEquals(8, searchAlgo.searchRecursive(array, 9))
assertEquals(9, searchAlgo.searchRecursive(array, 10))
}
@Test
fun `test bounds`() {
val array = arrayOf(1, 2, 3, 4, 6, 7, 8, 10)
assertEquals(-1, searchAlgo.leftBound(array, 0))
assertEquals(-1, searchAlgo.leftBound(array, 1))
assertEquals(1, searchAlgo.leftBound(array, 3))
assertEquals(3, searchAlgo.leftBound(array, 5))
assertEquals(6, searchAlgo.leftBound(array, 10))
assertEquals(7, searchAlgo.leftBound(array, 11))
assertEquals(7, searchAlgo.leftBound(array, 100))
assertEquals(0, searchAlgo.rightBound(array, 0))
assertEquals(0, searchAlgo.rightBound(array, 1))
assertEquals(2, searchAlgo.rightBound(array, 3))
assertEquals(4, searchAlgo.rightBound(array, 5))
assertEquals(7, searchAlgo.rightBound(array, 10))
assertEquals(8, searchAlgo.rightBound(array, 11))
assertEquals(8, searchAlgo.rightBound(array, 100))
}
}
================================================
FILE: src/test/kotlin/search/LinearSearchTest.kt
================================================
package search
import org.junit.Test
import org.junit.Assert.assertEquals
internal class LinearSearchTest {
@Test
fun test() {
val searchAlgo = LinearSearch()
val array = arrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
assertEquals(-1, searchAlgo.search(emptyArray(), 0))
assertEquals(-1, searchAlgo.search(array, 0))
assertEquals(-1, searchAlgo.search(array, 11))
assertEquals(0, searchAlgo.search(array, 1))
assertEquals(2, searchAlgo.search(array, 3))
assertEquals(4, searchAlgo.search(array, 5))
assertEquals(6, searchAlgo.search(array, 7))
assertEquals(8, searchAlgo.search(array, 9))
assertEquals(9, searchAlgo.search(array, 10))
}
}
================================================
FILE: src/test/kotlin/sorting/BubbleSortTest.kt
================================================
package sorting
import org.junit.Test
import org.junit.Assert.assertArrayEquals
import kotlin.random.Random
internal class BubbleSortTest {
private val bubbleSort = BubbleSort()
@Test
fun `test sort`() {
val expected1 = Array(1000) { it }
val actual1 = expected1.reversedArray()
bubbleSort.sort(actual1)
assertArrayEquals(expected1, actual1)
val actual2 = Array(1000) { Random.nextInt(1000) }
val expected2 = actual2.sortedArray()
bubbleSort.sort(actual2)
assertArrayEquals(expected2, actual2)
val expected3 = Array(1000) { it }
val actual3 = expected3.copyOf()
actual3.shuffle()
bubbleSort.sort(actual3)
assertArrayEquals(expected3, actual3)
val expected4 = Array(1000) { it }
val actual4 = expected3.copyOf()
bubbleSort.sort(actual3)
assertArrayEquals(expected4, actual4)
}
@Test
fun `test sort improved`() {
val expected1 = Array(1000) { it }
val actual1 = expected1.reversedArray()
bubbleSort.sortImproved(actual1)
assertArrayEquals(expected1, actual1)
val actual2 = Array(1000) { Random.nextInt(1000) }
val expected2 = actual2.sortedArray()
bubbleSort.sortImproved(actual2)
assertArrayEquals(expected2, actual2)
val expected3 = Array(1000) { it }
val actual3 = expected3.copyOf()
actual3.shuffle()
bubbleSort.sortImproved(actual3)
assertArrayEquals(expected3, actual3)
val expected4 = Array(1000) { it }
val actual4 = expected3.copyOf()
bubbleSort.sortImproved(actual3)
assertArrayEquals(expected4, actual4)
}
}
================================================
FILE: src/test/kotlin/sorting/CountingSortTest.kt
================================================
package sorting
import org.junit.Test
import org.junit.Assert.assertArrayEquals
class CountingSortTest {
@Test
fun test() {
val countingSort = CountingSort()
val actual1 = arrayOf(
5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 3, 4, 3, 4, 3, 3, 0,
0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 5, 3, 2, 2, 1, 1, 0
)
val expected1 = actual1.sortedArray()
countingSort.sort(actual1,0, 5)
assertArrayEquals(expected1, actual1)
val actual2 = arrayOf(9, 9, 9, 10, 10, 5, 4, 4, 4, 1, 1, 1, 3, 3, 3)
val expected2 = actual2.sortedArray()
countingSort.sort(actual2, 1, 10)
assertArrayEquals(expected2, actual2)
val actual3 = arrayOf(
1000, 1000, 555, 555, 555, 333, 222, 222, 1, 1, 1, 222, 222, 555, 587, 587, 1, 587,
1000, 1000, 1000, 6, 7, 6, 7, 7, 7, 6, 1, 1, 222, 555, 587, 3, 3, 3, 1, 3, 3, 6, 6,
49, 587, 587, 49, 49, 49, 100, 100, 1000, 100, 1000, 555, 222
)
val expected3 = actual3.sortedArray()
countingSort.sort(actual3, 1, 1000)
assertArrayEquals(expected3, actual3)
}
}
================================================
FILE: src/test/kotlin/sorting/InsertionSortTest.kt
================================================
package sorting
import org.junit.Test
import org.junit.Assert.assertArrayEquals
import kotlin.random.Random
internal class InsertionSortTest {
@Test
fun `test sort`() {
val insertionSort = InsertionSort()
val expected1 = Array(1000) { it }
val actual1 = expected1.reversedArray()
insertionSort.sort(actual1)
assertArrayEquals(expected1, actual1)
val actual2 = Array(1000) { Random.nextInt(1000) }
val expected2 = actual2.sortedArray()
insertionSort.sort(actual2)
assertArrayEquals(expected2, actual2)
val expected3 = Array(1000) { it }
val actual3 = expected3.copyOf()
actual3.shuffle()
insertionSort.sort(actual3)
assertArrayEquals(expected3, actual3)
val expected4 = Array(1000) { it }
val actual4 = expected3.copyOf()
insertionSort.sort(actual3)
assertArrayEquals(expected4, actual4)
}
}
================================================
FILE: src/test/kotlin/sorting/MergeSortTest.kt
================================================
package sorting
import org.junit.Test
import kotlin.random.Random
import org.junit.Assert.assertArrayEquals
class MergeSortTest {
private val mergeSort = MergeSort()
@Test
fun `test sort`() {
val expected1 = Array(1_000_000) { it }
val actual1 = expected1.reversedArray()
mergeSort.sort(actual1)
assertArrayEquals(expected1, actual1)
val actual2 = Array(1_000_000) { Random.nextInt(1_000_000) }
val expected2 = actual2.sortedArray()
mergeSort.sort(actual2)
assertArrayEquals(expected2, actual2)
val expected3 = Array(1_000_000) { it }
val actual3 = expected3.copyOf()
actual3.shuffle()
mergeSort.sort(actual3)
assertArrayEquals(expected3, actual3)
val expected4 = Array(1_000_000) { it }
val actual4 = expected3.copyOf()
mergeSort.sort(actual3)
assertArrayEquals(expected4, actual4)
}
@Test
fun `test sort recursive`() {
val expected1 = Array(1_000_000) { it }
val actual1 = expected1.reversedArray()
mergeSort.sortRecursive(actual1)
assertArrayEquals(expected1, actual1)
val actual2 = Array(1_000_000) { Random.nextInt(1_000_000) }
val expected2 = actual2.sortedArray()
mergeSort.sortRecursive(actual2)
assertArrayEquals(expected2, actual2)
val expected3 = Array(1_000_000) { it }
val actual3 = expected3.copyOf()
actual3.shuffle()
mergeSort.sortRecursive(actual3)
assertArrayEquals(expected3, actual3)
val expected4 = Array(1_000_000) { it }
val actual4 = expected3.copyOf()
mergeSort.sortRecursive(actual3)
assertArrayEquals(expected4, actual4)
}
}
================================================
FILE: src/test/kotlin/sorting/QuickSortTest.kt
================================================
package sorting
import org.junit.Test
import kotlin.random.Random
import org.junit.Assert.assertArrayEquals
class QuickSortTest {
@Test
fun `test sort`() {
val quickSort = QuickSort()
val expected1 = Array(1_000_000) { it }
val actual1 = expected1.reversedArray()
quickSort.sort(actual1)
assertArrayEquals(expected1, actual1)
val actual2 = Array(1_000_000) { Random.nextInt(1_000_000) }
val expected2 = actual2.sortedArray()
quickSort.sort(actual2)
assertArrayEquals(expected2, actual2)
val expected3 = Array(1_000_000) { it }
val actual3 = expected3.copyOf()
actual3.shuffle()
quickSort.sort(actual3)
assertArrayEquals(expected3, actual3)
val expected4 = Array(1_000_000) { it }
val actual4 = expected3.copyOf()
quickSort.sort(actual3)
assertArrayEquals(expected4, actual4)
}
}
================================================
FILE: src/test/kotlin/sorting/RadixSortTest.kt
================================================
package sorting
import org.junit.Test
import org.junit.Assert.assertArrayEquals
import kotlin.random.Random
class RadixSortTest {
@Test
fun test() {
val radixSort = RadixSort()
val expected1 = Array(1_000_000) { it }
val actual1 = expected1.reversedArray()
radixSort.sort(actual1)
assertArrayEquals(expected1, actual1)
val actual2 = Array(1_000_000) { Random.nextInt(1_000_000) }
val expected2 = actual2.sortedArray()
radixSort.sort(actual2)
assertArrayEquals(expected2, actual2)
val expected3 = Array(1_000_000) { it }
val actual3 = expected3.copyOf()
actual3.shuffle()
radixSort.sort(actual3)
assertArrayEquals(expected3, actual3)
val expected4 = Array(1_000_000) { it }
val actual4 = expected3.copyOf()
radixSort.sort(actual3)
assertArrayEquals(expected4, actual4)
}
}
================================================
FILE: src/test/kotlin/sorting/SelectionSortTest.kt
================================================
package sorting
import org.junit.Test
import org.junit.Assert.assertArrayEquals
import kotlin.random.Random
class SelectionSortTest {
@Test
fun test() {
val selectionSort = SelectionSort()
val expected1 = Array(1000) { it }
val actual1 = expected1.reversedArray()
selectionSort.sort(actual1)
assertArrayEquals(expected1, actual1)
val actual2 = Array(1000) { Random.nextInt(1000) }
val expected2 = actual2.sortedArray()
selectionSort.sort(actual2)
assertArrayEquals(expected2, actual2)
val expected3 = Array(1000) { it }
val actual3 = expected3.copyOf()
actual3.shuffle()
selectionSort.sort(actual3)
assertArrayEquals(expected3, actual3)
val expected4 = Array(1000) { it }
val actual4 = expected3.copyOf()
selectionSort.sort(actual3)
assertArrayEquals(expected4, actual4)
}
}
================================================
FILE: src/test/kotlin/sorting/TimSortTest.kt
================================================
package sorting
import org.junit.Test
import kotlin.random.Random
import org.junit.Assert.assertArrayEquals
class TimSortTest {
@Test
fun `test sort`() {
val timSort = TimSort()
val expected1 = Array(1_000_000) { it }
val actual1 = expected1.reversedArray()
timSort.sort(actual1)
assertArrayEquals(expected1, actual1)
val actual2 = Array(1_000_000) { Random.nextInt(1_000_000) }
val expected2 = actual2.sortedArray()
timSort.sort(actual2)
assertArrayEquals(expected2, actual2)
val expected3 = Array(1_000_000) { it }
val actual3 = expected3.copyOf()
actual3.shuffle()
timSort.sort(actual3)
assertArrayEquals(expected3, actual3)
val expected4 = Array(1_000_000) { it }
val actual4 = expected3.copyOf()
timSort.sort(actual3)
assertArrayEquals(expected4, actual4)
}
}
================================================
FILE: src/test/kotlin/structures/BinaryTreeTest.kt
================================================
package structures
import org.junit.Test
import org.junit.Assert.assertEquals
internal class BinaryTreeTest {
@Test
fun `test add`() {
val tree = BinaryTree()
tree.add(5)
tree.add(10)
tree.add(4)
assertEquals(listOf(5, 4, 10), tree.traverseLevelOrder())
tree.add(9)
assertEquals(listOf(5, 4, 10, 9), tree.traverseLevelOrder())
tree.add(1)
assertEquals(listOf(5, 4, 10, 1, 9), tree.traverseLevelOrder())
tree.add(11)
assertEquals(listOf(5, 4, 10, 1, 9, 11), tree.traverseLevelOrder())
}
@Test
fun `test remove`() {
val tree = BinaryTree()
tree.add(10)
tree.add(20)
tree.add(30)
assertEquals(listOf(10, 20, 30), tree.traverseLevelOrder())
assertEquals(false, tree.isEmpty)
tree.remove(20)
assertEquals(listOf(10, 30), tree.traverseLevelOrder())
assertEquals(false, tree.isEmpty)
tree.remove(10)
assertEquals(listOf(30), tree.traverseLevelOrder())
assertEquals(false, tree.isEmpty)
tree.remove(30)
assertEquals(emptyList(), tree.traverseLevelOrder())
assertEquals(true, tree.isEmpty)
}
@Test
fun `test is empty`() {
val tree = BinaryTree()
assertEquals(true, tree.isEmpty)
tree.add(10)
assertEquals(false, tree.isEmpty)
tree.add(20)
assertEquals(false, tree.isEmpty)
tree.remove(10)
assertEquals(false, tree.isEmpty)
tree.remove(20)
assertEquals(true, tree.isEmpty)
}
@Test
fun `test contains`() {
val tree = BinaryTree()
assertEquals(false, tree.contains(5))
assertEquals(false, tree.contains(3))
assertEquals(false, tree.contains(7))
tree.add(5)
tree.add(3)
tree.add(7)
assertEquals(true, tree.contains(5))
assertEquals(true, tree.contains(3))
assertEquals(true, tree.contains(7))
assertEquals(false, tree.contains(2))
assertEquals(false, tree.contains(10))
tree.add(2)
tree.add(10)
assertEquals(true, tree.contains(2))
assertEquals(true, tree.contains(10))
tree.remove(5)
tree.remove(3)
tree.remove(7)
tree.remove(2)
assertEquals(false, tree.contains(5))
assertEquals(false, tree.contains(3))
assertEquals(false, tree.contains(7))
assertEquals(false, tree.contains(2))
assertEquals(true, tree.contains(10))
}
@Test
fun `test traverseInOrder`() {
val tree = BinaryTree()
assertEquals(emptyList(), tree.traverseInOrder())
tree.add(5)
tree.add(3)
tree.add(8)
tree.add(2)
tree.add(9)
assertEquals(listOf(2, 3, 5, 8, 9), tree.traverseInOrder())
tree.add(1)
tree.add(11)
assertEquals(listOf(1, 2, 3, 5, 8, 9, 11), tree.traverseInOrder())
tree.add(20)
tree.add(30)
assertEquals(listOf(1, 2, 3, 5, 8, 9, 11, 20, 30), tree.traverseInOrder())
}
@Test
fun `test traversePreOrder`() {
val tree = BinaryTree()
assertEquals(emptyList(), tree.traversePreOrder())
tree.add(5)
tree.add(3)
tree.add(8)
tree.add(2)
tree.add(9)
assertEquals(listOf(5, 3, 2, 8, 9), tree.traversePreOrder())
tree.add(1)
tree.add(11)
assertEquals(listOf(5, 3, 2, 1, 8, 9, 11), tree.traversePreOrder())
tree.add(0)
tree.add(20)
assertEquals(listOf(5, 3, 2, 1, 0, 8, 9, 11, 20), tree.traversePreOrder())
}
@Test
fun `test traversePostOrder`() {
val tree = BinaryTree()
assertEquals(emptyList(), tree.traversePostOrder())
tree.add(5)
tree.add(3)
tree.add(8)
tree.add(2)
tree.add(9)
assertEquals(listOf(2, 3, 9, 8, 5), tree.traversePostOrder())
tree.add(1)
tree.add(11)
assertEquals(listOf(1, 2, 3, 11, 9, 8, 5), tree.traversePostOrder())
tree.add(0)
tree.add(20)
assertEquals(listOf(0, 1, 2, 3, 20, 11, 9, 8, 5), tree.traversePostOrder())
}
@Test
fun `test traverseLevelOrder`() {
val tree = BinaryTree()
assertEquals(emptyList(), tree.traverseLevelOrder())
tree.add(5)
tree.add(3)
tree.add(8)
tree.add(2)
tree.add(9)
assertEquals(listOf(5, 3, 8, 2, 9), tree.traverseLevelOrder())
tree.add(1)
tree.add(11)
assertEquals(listOf(5, 3, 8, 2, 9, 1, 11), tree.traverseLevelOrder())
tree.add(0)
tree.add(20)
tree.add(30)
assertEquals(listOf(5, 3, 8, 2, 9, 1, 11, 0, 20, 30), tree.traverseLevelOrder())
}
}
================================================
FILE: src/test/kotlin/structures/CircularLinkedListTest.kt
================================================
package structures
import org.junit.Test
import org.junit.Assert.assertEquals
internal class CircularLinkedListTest {
@Test
fun `test cyclingList`() {
val list = CircularLinkedList()
list.add(3)
list.add(6)
list.add(9)
list.add(12)
assertEquals(emptyList(), list.cyclingList(0))
assertEquals(listOf(3, 6, 9, 12), list.cyclingList(1))
assertEquals(listOf(
3, 6, 9, 12,
3, 6, 9, 12
), list.cyclingList(2))
assertEquals(listOf(
3, 6, 9, 12,
3, 6, 9, 12,
3, 6, 9, 12
), list.cyclingList(3))
list.remove(6)
assertEquals(listOf(
3, 9, 12, 3, 9, 12,
3, 9, 12, 3, 9, 12,
3, 9, 12, 3, 9, 12
), list.cyclingList(6))
list.remove(9)
assertEquals(listOf(
3, 12, 3, 12, 3, 12,
3, 12, 3, 12, 3, 12,
3, 12, 3, 12, 3, 12,
3, 12, 3, 12, 3, 12
), list.cyclingList(12))
list.remove(12)
assertEquals(List(100) { 3 }, list.cyclingList(100))
list.remove(3)
assertEquals(emptyList(), list.cyclingList(0))
assertEquals(emptyList(), list.cyclingList(1))
assertEquals(emptyList(), list.cyclingList(3))
assertEquals(emptyList(), list.cyclingList(1000))
}
@Test
fun `test is empty`() {
val list = CircularLinkedList()
assertEquals(true, list.isEmpty)
list.add(1)
list.add(2)
list.add(3)
assertEquals(false, list.isEmpty)
list.remove(1)
list.remove(2)
list.remove(3)
assertEquals(true, list.isEmpty)
}
@Test
fun `test add by index`() {
val list = CircularLinkedList()
list.add(1)
list.add(3)
list.add(5)
assertEquals("""
size: 3
elements: 1 - 3 - 5 -
""".trimIndent(), list.toString())
list.add(1, 2)
list.add(3, 4)
assertEquals("""
size: 5
elements: 1 - 2 - 3 - 4 - 5 -
""".trimIndent(), list.toString())
}
@Test
fun `test addFirst`() {
val list = CircularLinkedList()
list.addFirst(100)
list.addFirst(80)
list.addFirst(60)
list.addFirst(40)
list.addFirst(20)
assertEquals("""
size: 5
elements: 20 - 40 - 60 - 80 - 100 -
""".trimIndent(), list.toString())
list.remove(80)
list.remove(40)
assertEquals("""
size: 3
elements: 20 - 60 - 100 -
""".trimIndent(), list.toString())
list.addFirst(0)
assertEquals("""
size: 4
elements: 0 - 20 - 60 - 100 -
""".trimIndent(), list.toString())
}
@Test
fun `test addLast`() {
val list = CircularLinkedList()
list.addLast(100)
list.addLast(200)
list.addLast(300)
list.addLast(400)
list.addLast(500)
list.addLast(600)
list.addLast(700)
assertEquals("""
size: 7
elements: 100 - 200 - 300 - 400 - 500 - 600 - 700 -
""".trimIndent(), list.toString())
list.remove(200)
list.remove(400)
list.remove(600)
assertEquals("""
size: 4
elements: 100 - 300 - 500 - 700 -
""".trimIndent(), list.toString())
list.addLast(900)
assertEquals("""
size: 5
elements: 100 - 300 - 500 - 700 - 900 -
""".trimIndent(), list.toString())
}
@Test
fun `test contains`() {
val list = CircularLinkedList()
list.add(1)
list.add(3)
list.add(5)
list.add(7)
list.add(9)
list.add(11)
assertEquals(true, list.contains(1))
assertEquals(true, list.contains(5))
assertEquals(true, list.contains(9))
assertEquals(true, list.contains(11))
assertEquals(false, list.contains(2))
assertEquals(false, list.contains(4))
assertEquals(false, list.contains(8))
assertEquals(false, list.contains(10))
list.clear()
assertEquals(false, list.contains(1))
assertEquals(false, list.contains(5))
assertEquals(false, list.contains(9))
assertEquals(false, list.contains(11))
}
@Test
fun `test remove and clear`() {
val list = CircularLinkedList()
list.add(1)
list.add(2)
list.add(3)
list.add(4)
list.add(5)
assertEquals("""
size: 5
elements: 1 - 2 - 3 - 4 - 5 -
""".trimIndent(), list.toString())
assertEquals(true, list.remove(1))
assertEquals(true, list.remove(3))
assertEquals(true, list.remove(5))
assertEquals("""
size: 2
elements: 2 - 4 -
""".trimIndent(), list.toString())
println(list.toString())
assertEquals(true, list.remove(2))
println(list.toString())
assertEquals(true, list.remove(4))
assertEquals(true, list.isEmpty)
list.add(6)
list.add(7)
list.add(11)
list.add(13)
assertEquals("""
size: 4
elements: 6 - 7 - 11 - 13 -
""".trimIndent(), list.toString())
list.clear()
assertEquals(true, list.isEmpty)
}
}
================================================
FILE: src/test/kotlin/structures/DoubleLinkedListTest.kt
================================================
package structures
import org.junit.Test
import org.junit.Assert.assertEquals
internal class DoubleLinkedListTest {
@Test
fun `test is empty`() {
val list = DoubleLinkedList()
assertEquals(true, list.isEmpty)
list.add(1)
list.add(2)
list.add(3)
assertEquals(false, list.isEmpty)
list.remove(1)
list.remove(2)
list.remove(3)
assertEquals(true, list.isEmpty)
}
@Test
fun `test add by index`() {
val list = DoubleLinkedList()
list.add(1)
list.add(3)
list.add(5)
assertEquals("""
size: 3
elements: 1 -- 3 -- 5
""".trimIndent(), list.toString())
list.add(1, 2)
list.add(3, 4)
assertEquals("""
size: 5
elements: 1 -- 2 -- 3 -- 4 -- 5
""".trimIndent(), list.toString())
}
@Test
fun `test addFirst`() {
val list = DoubleLinkedList()
list.addFirst(100)
list.addFirst(80)
list.addFirst(60)
list.addFirst(40)
list.addFirst(20)
assertEquals("""
size: 5
elements: 20 -- 40 -- 60 -- 80 -- 100
""".trimIndent(), list.toString())
list.remove(80)
list.remove(40)
assertEquals("""
size: 3
elements: 20 -- 60 -- 100
""".trimIndent(), list.toString())
list.addFirst(0)
assertEquals("""
size: 4
elements: 0 -- 20 -- 60 -- 100
""".trimIndent(), list.toString())
}
@Test
fun `test addLast`() {
val list = DoubleLinkedList()
list.addLast(100)
list.addLast(200)
list.addLast(300)
list.addLast(400)
list.addLast(500)
list.addLast(600)
list.addLast(700)
assertEquals("""
size: 7
elements: 100 -- 200 -- 300 -- 400 -- 500 -- 600 -- 700
""".trimIndent(), list.toString())
list.remove(200)
list.remove(400)
list.remove(600)
assertEquals("""
size: 4
elements: 100 -- 300 -- 500 -- 700
""".trimIndent(), list.toString())
list.addLast(900)
assertEquals("""
size: 5
elements: 100 -- 300 -- 500 -- 700 -- 900
""".trimIndent(), list.toString())
}
@Test
fun `test contains`() {
val list = DoubleLinkedList()
list.add(1)
list.add(3)
list.add(5)
list.add(7)
list.add(9)
list.add(11)
assertEquals(true, list.contains(1))
assertEquals(true, list.contains(5))
assertEquals(true, list.contains(9))
assertEquals(true, list.contains(11))
assertEquals(false, list.contains(2))
assertEquals(false, list.contains(4))
assertEquals(false, list.contains(8))
assertEquals(false, list.contains(10))
list.clear()
assertEquals(false, list.contains(1))
assertEquals(false, list.contains(5))
assertEquals(false, list.contains(9))
assertEquals(false, list.contains(11))
}
@Test
fun `test remove and clear`() {
val list = DoubleLinkedList()
list.add(1)
list.add(2)
list.add(3)
list.add(4)
list.add(5)
assertEquals("""
size: 5
elements: 1 -- 2 -- 3 -- 4 -- 5
""".trimIndent(), list.toString())
assertEquals(true, list.remove(1))
assertEquals(true, list.remove(3))
assertEquals(true, list.remove(5))
assertEquals("""
size: 2
elements: 2 -- 4
""".trimIndent(), list.toString())
assertEquals(true, list.remove(2))
assertEquals(true, list.remove(4))
assertEquals(true, list.isEmpty)
list.add(6)
list.add(7)
list.add(11)
list.add(13)
assertEquals("""
size: 4
elements: 6 -- 7 -- 11 -- 13
""".trimIndent(), list.toString())
list.clear()
assertEquals(true, list.isEmpty)
}
@Test
fun `test list and reversedList`() {
val list = DoubleLinkedList()
list.add(1)
list.add(2)
list.add(3)
list.add(4)
list.add(5)
list.add(6)
list.add(7)
assertEquals(listOf(1, 2, 3, 4, 5, 6, 7), list.list)
assertEquals(listOf(7, 6, 5, 4, 3, 2, 1), list.reversedList)
list.remove(1)
list.remove(4)
list.remove(7)
assertEquals(listOf(2, 3, 5, 6), list.list)
assertEquals(listOf(6, 5, 3, 2), list.reversedList)
list.remove(2)
list.remove(6)
assertEquals(listOf(3, 5), list.list)
assertEquals(listOf(5, 3), list.reversedList)
list.clear()
assertEquals(emptyList(), list.list)
assertEquals(emptyList(), list.reversedList)
assertEquals(true, list.isEmpty)
}
}
================================================
FILE: src/test/kotlin/structures/DynamicArrayTest.kt
================================================
package structures
import org.junit.Test
import org.junit.Assert.assertEquals
internal class DynamicArrayTest {
@Test
fun test() {
val array = DynamicArray()
array.add(1)
array.add(2)
array.add(3)
array.add(4)
assertEquals("""
capacity: 10
size: 4
elements: 1, 2, 3, 4
""".trimIndent(), array.toString())
assertEquals(1, array.set(0, 10))
assertEquals(10, array.get(0))
assertEquals(2, array.set(1, 20))
assertEquals(20, array.get(1))
assertEquals(3, array.set(2, 30))
assertEquals(30, array.get(2))
assertEquals(4, array.set(3, 40))
assertEquals(40, array.get(3))
assertEquals(true, array.remove(10))
assertEquals(true, array.remove(20))
assertEquals(true, array.remove(30))
assertEquals(true, array.remove(40))
array.add(1); array.add(2); array.add(3); array.add(4); array.add(5)
array.add(6); array.add(7); array.add(8); array.add(9); array.add(10)
array.add(11); array.add(12); array.add(13); array.add(14); array.add(15)
assertEquals("""
capacity: 20
size: 15
elements: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
""".trimIndent(), array.toString())
}
}
================================================
FILE: src/test/kotlin/structures/GraphTest.kt
================================================
package structures
import org.junit.Test
import org.junit.Assert.assertEquals
internal class GraphTest {
@Test
fun `test add and remove vertexes`() {
val graph = Graph()
graph.addVertex(10)
graph.addVertex(20)
graph.addVertex(30)
graph.addEdge(10, 20)
graph.addEdge(10, 30)
graph.addEdge(20, 30)
assertEquals(listOf(20, 30), graph.connectedVertexes(10))
assertEquals(listOf(10, 30), graph.connectedVertexes(20))
graph.removeVertex(10)
assertEquals(listOf(20), graph.connectedVertexes(30))
assertEquals(listOf(30), graph.connectedVertexes(20))
graph.removeVertex(20)
assertEquals(listOf(), graph.connectedVertexes(30))
}
@Test
fun `test remove edges`() {
val graph = Graph()
graph.addVertex(10)
graph.addVertex(20)
graph.addVertex(30)
graph.addEdge(10, 20)
graph.addEdge(10, 30)
graph.addEdge(20, 30)
assertEquals(listOf(20, 30), graph.connectedVertexes(10))
graph.removeEdge(10, 20)
assertEquals(listOf(30), graph.connectedVertexes(10))
graph.removeEdge(10, 30)
assertEquals(listOf(), graph.connectedVertexes(10))
assertEquals(listOf(30), graph.connectedVertexes(20))
graph.removeEdge(20, 30)
assertEquals(listOf(), graph.connectedVertexes(20))
}
@Test
fun `test depthFirstTraversal`() {
val graph = Graph()
graph.addVertex(10)
graph.addVertex(20)
graph.addVertex(30)
graph.addEdge(10, 20)
graph.addEdge(20, 30)
graph.addEdge(30, 10)
assertEquals(listOf(10, 20, 30), graph.depthFirstTraversal())
graph.removeVertex(10)
assertEquals(listOf(20, 30), graph.depthFirstTraversal())
graph.removeVertex(30)
assertEquals(listOf(20), graph.depthFirstTraversal())
graph.removeVertex(20)
assertEquals(listOf(), graph.depthFirstTraversal())
}
@Test
fun `test breadthFirstTraversal`() {
val graph = Graph()
graph.addVertex(10)
graph.addVertex(20)
graph.addVertex(30)
graph.addVertex(40)
graph.addEdge(10, 20)
graph.addEdge(20, 30)
graph.addEdge(20, 40)
assertEquals(listOf(10, 20, 30, 40), graph.breadthFirstTraversal())
graph.removeVertex(10)
assertEquals(listOf(20, 30, 40), graph.breadthFirstTraversal())
graph.removeVertex(40)
assertEquals(listOf(20, 30), graph.breadthFirstTraversal())
graph.removeVertex(20)
graph.removeVertex(30)
assertEquals(listOf(), graph.breadthFirstTraversal())
}
}
================================================
FILE: src/test/kotlin/structures/GraphWithWeightsTest.kt
================================================
package structures
import org.junit.Test
import org.junit.Assert.assertEquals
class GraphWithWeightsTest {
@Test
fun `test add and remove vertexes`() {
val graph = GraphWithWeights()
graph.addVertex(10)
graph.addVertex(20)
graph.addVertex(30)
graph.addEdge(10, 20, 1)
graph.addEdge(10, 30, 2)
graph.addEdge(20, 30, 3)
assertEquals(listOf(
"vertex -> 20, cost -> 1",
"vertex -> 30, cost -> 2"
), graph.connectedVertexesWithWeights(10))
graph.removeVertex(10)
assertEquals(listOf(), graph.connectedVertexesWithWeights(10))
assertEquals(listOf("vertex -> 30, cost -> 3"), graph.connectedVertexesWithWeights(20))
graph.removeVertex(20)
assertEquals(listOf(), graph.connectedVertexesWithWeights(10))
}
@Test
fun `test remove edges`() {
val graph = GraphWithWeights()
graph.addVertex(10)
graph.addVertex(20)
graph.addVertex(30)
graph.addEdge(10, 20, 1)
graph.addEdge(10, 30, 2)
graph.addEdge(20, 30, 3)
assertEquals(listOf(
"vertex -> 20, cost -> 1",
"vertex -> 30, cost -> 2"
), graph.connectedVertexesWithWeights(10))
graph.removeEdge(10, 20)
assertEquals(listOf("vertex -> 30, cost -> 2"), graph.connectedVertexesWithWeights(10))
graph.removeEdge(10, 30)
assertEquals(listOf(), graph.connectedVertexesWithWeights(10))
assertEquals(listOf("vertex -> 30, cost -> 3"), graph.connectedVertexesWithWeights(20))
graph.removeEdge(20, 30)
assertEquals(listOf(), graph.connectedVertexesWithWeights(10))
}
@Test
fun test_dijkstraAlgorithm() {
val graph = GraphWithWeights()
graph.addVertex(1)
graph.addVertex(2)
graph.addVertex(3)
graph.addVertex(4)
graph.addVertex(5)
graph.addEdge(1, 2, 10)
graph.addEdge(1, 5, 100)
graph.addEdge(2, 3, 20)
graph.addEdge(2, 4, 5)
graph.addEdge(3, 4, 15)
graph.addEdge(4, 5, 5)
assertEquals(linkedMapOf(
1 to 0,
2 to 10,
3 to 30,
4 to 15,
5 to 20
), graph.dijkstraAlgorithm())
graph.removeVertex(4)
assertEquals(linkedMapOf(
1 to 0,
2 to 10,
3 to 30,
5 to 100
), graph.dijkstraAlgorithm())
graph.removeVertex(5)
assertEquals(linkedMapOf(
1 to 0,
2 to 10,
3 to 30
), graph.dijkstraAlgorithm())
graph.removeVertex(1)
graph.removeVertex(2)
graph.removeVertex(3)
assertEquals(mapOf(), graph.dijkstraAlgorithm())
}
}
================================================
FILE: src/test/kotlin/structures/MatrixTest.kt
================================================
package structures
import org.junit.Test
import org.junit.Assert.assertEquals
import org.junit.Assert.assertThrows
import java.lang.IllegalArgumentException
class MatrixTest {
@Test
fun `test when number of elements in each row is not the same`() {
assertThrows(IllegalArgumentException::class.java) {
matrix {
row(1, 2, 3)
row(4, 5)
}
}
}
@Test
fun `test equals`() {
val matrix1 = matrix {
row(1, 2, 3)
row(4, 5, 6)
row(7, 8, 9)
}
val matrix2 = matrix {
row(1, 2, 3)
row(4, 5, 6)
row(7, 8, 9)
}
assertEquals(true, matrix1 == matrix2)
val matrix3 = matrix {
row(1, 2, 3)
row(4, 5, 6)
}
assertEquals(false, matrix2 == matrix3)
}
@Test
fun `test plus minus a value`() {
val matrix1 = matrix {
row(4, 7, 2)
row(10, 12, 20)
row(100, 1000, 8)
}
val expected1 = matrix {
row(6, 9, 4)
row(12, 14, 22)
row(102, 1002, 10)
}
val actual1 = matrix1 + 2
assertEquals(expected1, actual1)
val actual2 = matrix1 - 10
val expected2 = matrix {
row(-6, -3, -8)
row(0, 2, 10)
row(90, 990, -2)
}
assertEquals(expected2, actual2)
}
@Test
fun `test multiply and div by value`() {
val matrix1 = matrix {
row(2, 5)
row(10, 19)
}
val expected1 = matrix {
row(4, 10)
row(20, 38)
}
val actual1 = matrix1 * 2
assertEquals(expected1, actual1)
val matrix2 = matrix {
row(100, -95, 1200)
row(55, 110, -20)
row(5, 2, -10)
}
val actual2 = matrix2 / 5
val expected2 = matrix {
row(20, -19, 240)
row(11, 22, -4)
row(1, 0, -2)
}
assertEquals(expected2, actual2)
}
@Test
fun `test plus between matrices`() {
val matrix1 = matrix {
row(13, 109)
row(8, 6)
}
val matrix2 = matrix {
row(9, 34, 2)
row(90, 20, 1005)
}
assertThrows(IllegalArgumentException::class.java) {
matrix1 + matrix2
}
val matrix3 = matrix {
row(20, 30)
row(3, 56)
row(5, 28)
}
assertThrows(IllegalArgumentException::class.java) {
matrix1 + matrix3
}
val matrix4 = matrix {
row(7, 1)
row(2, 4)
}
val expected = matrix {
row(20, 110)
row(10, 10)
}
val actual = matrix1 + matrix4
assertEquals(expected, actual)
}
@Test
fun `test minus between matrices`() {
val matrix1 = matrix {
row(13, 109)
row(8, 6)
}
val matrix2 = matrix {
row(9, 34, 2)
row(90, 20, 1005)
}
assertThrows(IllegalArgumentException::class.java) {
matrix1 - matrix2
}
val matrix3 = matrix {
row(20, 30)
row(3, 56)
row(5, 28)
}
assertThrows(IllegalArgumentException::class.java) {
matrix1 - matrix3
}
val matrix4 = matrix {
row(3, 9)
row(8, 6)
}
val expected = matrix {
row(10, 100)
row(0, 0)
}
val actual = matrix1 - matrix4
assertEquals(expected, actual)
}
@Test
fun `test multiply between matrices`() {
val matrix1 = matrix {
row(1, 2)
row(8, 9)
}
val matrix2 = matrix {
row(2)
row(4)
row(8)
}
assertThrows(IllegalArgumentException::class.java) { matrix1 * matrix2 }
val matrix3 = matrix {
row(1, 4)
row(2, 5)
row(3, 6)
}
val matrix4 = matrix {
row(7, 8, 9, 10)
row(11, 12, 13, 14)
}
val expected1 = matrix {
row(51, 56, 61, 66)
row(69, 76, 83, 90)
row(87, 96, 105, 114)
}
val actual1 = matrix3 * matrix4
assertEquals(expected1, actual1)
val matrix5 = matrix {
row(45, 11, 20, -15)
row(-12, 9, -18, 0)
row(8, 3, -13, 36)
}
val matrix6 = matrix {
row(-1, 8, 55)
row(5, -2, 13)
row(14, 27, 6)
row(19, 3, -10)
}
val expected2 = matrix {
row(5, 833, 2888)
row(-195, -600, -651)
row(509, -185, 41)
}
val actual2 = matrix5 * matrix6
assertEquals(expected2, actual2)
}
}
================================================
FILE: src/test/kotlin/structures/MaxHeapTest.kt
================================================
package structures
import org.junit.Test
import org.junit.Assert.assertEquals
internal class MaxHeapTest {
@Test
fun `test operations`() {
val heap = MaxHeap(10)
assertEquals(true, heap.isEmpty)
heap.add(10)
heap.add(17)
heap.add(20)
assertEquals(false, heap.isEmpty)
assertEquals(20, heap.peekMax())
assertEquals(20, heap.popMax())
heap.add(1)
heap.add(5)
assertEquals(17, heap.peekMax())
assertEquals(17, heap.popMax())
assertEquals(10, heap.peekMax())
assertEquals(10, heap.popMax())
heap.set(1, 100)
assertEquals(100, heap.peekMax())
assertEquals(100, heap.popMax())
assertEquals(1, heap.peekMax())
assertEquals(1, heap.popMax())
assertEquals(true, heap.isEmpty)
}
@Test
fun `test creating from array`() {
val array = intArrayOf(10, 2, 11, 17, 5, -1, 9, 0)
val heap = MaxHeap.create(array)
assertEquals(17, heap.popMax())
assertEquals(11, heap.popMax())
assertEquals(10, heap.popMax())
assertEquals(9, heap.popMax())
assertEquals(5, heap.popMax())
assertEquals(2, heap.popMax())
assertEquals(0, heap.popMax())
assertEquals(-1, heap.popMax())
assertEquals(true, heap.isEmpty)
}
}
================================================
FILE: src/test/kotlin/structures/MinHeapTest.kt
================================================
package structures
import org.junit.Test
import org.junit.Assert.assertEquals
internal class MinHeapTest {
@Test
fun `test operations`() {
val heap = MinHeap(10)
assertEquals(true, heap.isEmpty)
heap.add(10)
heap.add(17)
heap.add(20)
assertEquals(false, heap.isEmpty)
assertEquals(10, heap.peekMin())
assertEquals(10, heap.popMin())
heap.add(1)
heap.add(5)
assertEquals(1, heap.peekMin())
assertEquals(1, heap.popMin())
assertEquals(5, heap.peekMin())
assertEquals(5, heap.popMin())
heap.set(1, 15)
assertEquals(15, heap.peekMin())
assertEquals(15, heap.popMin())
assertEquals(20, heap.peekMin())
assertEquals(20, heap.popMin())
assertEquals(true, heap.isEmpty)
}
@Test
fun `test creating from array`() {
val array = intArrayOf(10, 2, 11, 17, 5, -1, 9, 0)
val heap = MinHeap.create(array)
assertEquals(-1, heap.popMin())
assertEquals(0, heap.popMin())
assertEquals(2, heap.popMin())
assertEquals(5, heap.popMin())
assertEquals(9, heap.popMin())
assertEquals(10, heap.popMin())
assertEquals(11, heap.popMin())
assertEquals(17, heap.popMin())
assertEquals(true, heap.isEmpty)
}
}
================================================
FILE: src/test/kotlin/structures/QueueTest.kt
================================================
package structures
import org.junit.Test
import org.junit.Assert.assertEquals
class QueueTest {
@Test
fun test() {
val queue = Queue()
assertEquals(true, queue.isEmpty)
assertEquals(0, queue.size)
queue.enqueue(1)
assertEquals(1, queue.peek())
queue.enqueue(2)
assertEquals(1, queue.peek())
queue.enqueue(3)
assertEquals(1, queue.peek())
assertEquals(false, queue.isEmpty)
assertEquals(3, queue.size)
assertEquals(1, queue.dequeue())
assertEquals(2, queue.peek())
assertEquals(2, queue.dequeue())
assertEquals(3, queue.peek())
assertEquals(3, queue.dequeue())
assertEquals(true, queue.isEmpty)
assertEquals(0, queue.size)
queue.enqueue(10)
queue.enqueue(20)
queue.enqueue(30)
assertEquals(false, queue.isEmpty)
assertEquals(3, queue.size)
queue.clear()
assertEquals(true, queue.isEmpty)
assertEquals(0, queue.size)
}
}
================================================
FILE: src/test/kotlin/structures/SingleLinkedListTest.kt
================================================
package structures
import org.junit.Test
import org.junit.Assert.assertEquals
internal class SingleLinkedListTest {
@Test
fun `test is empty`() {
val list = SingleLinkedList()
assertEquals(true, list.isEmpty)
list.add(1)
list.add(2)
list.add(3)
assertEquals(false, list.isEmpty)
list.remove(1)
list.remove(2)
list.remove(3)
assertEquals(true, list.isEmpty)
}
@Test
fun `test add by index`() {
val list = SingleLinkedList()
list.add(1)
list.add(3)
list.add(5)
assertEquals("""
size: 3
elements: 1 - 3 - 5
""".trimIndent(), list.toString())
list.add(1, 2)
list.add(3, 4)
assertEquals("""
size: 5
elements: 1 - 2 - 3 - 4 - 5
""".trimIndent(), list.toString())
}
@Test
fun `test addFirst`() {
val list = SingleLinkedList()
list.addFirst(100)
list.addFirst(80)
list.addFirst(60)
list.addFirst(40)
list.addFirst(20)
assertEquals("""
size: 5
elements: 20 - 40 - 60 - 80 - 100
""".trimIndent(), list.toString())
list.remove(80)
list.remove(40)
assertEquals("""
size: 3
elements: 20 - 60 - 100
""".trimIndent(), list.toString())
list.addFirst(0)
assertEquals("""
size: 4
elements: 0 - 20 - 60 - 100
""".trimIndent(), list.toString())
}
@Test
fun `test addLast`() {
val list = SingleLinkedList()
list.addLast(100)
list.addLast(200)
list.addLast(300)
list.addLast(400)
list.addLast(500)
list.addLast(600)
list.addLast(700)
assertEquals("""
size: 7
elements: 100 - 200 - 300 - 400 - 500 - 600 - 700
""".trimIndent(), list.toString())
list.remove(200)
list.remove(400)
list.remove(600)
assertEquals("""
size: 4
elements: 100 - 300 - 500 - 700
""".trimIndent(), list.toString())
list.addLast(900)
assertEquals("""
size: 5
elements: 100 - 300 - 500 - 700 - 900
""".trimIndent(), list.toString())
}
@Test
fun `test contains`() {
val list = SingleLinkedList()
list.add(1)
list.add(3)
list.add(5)
list.add(7)
list.add(9)
list.add(11)
assertEquals(true, list.contains(1))
assertEquals(true, list.contains(5))
assertEquals(true, list.contains(9))
assertEquals(true, list.contains(11))
assertEquals(false, list.contains(2))
assertEquals(false, list.contains(4))
assertEquals(false, list.contains(8))
assertEquals(false, list.contains(10))
list.clear()
assertEquals(false, list.contains(1))
assertEquals(false, list.contains(5))
assertEquals(false, list.contains(9))
assertEquals(false, list.contains(11))
}
@Test
fun `test remove and clear`() {
val list = SingleLinkedList()
list.add(1)
list.add(2)
list.add(3)
list.add(4)
list.add(5)
assertEquals("""
size: 5
elements: 1 - 2 - 3 - 4 - 5
""".trimIndent(), list.toString())
assertEquals(true, list.remove(1))
assertEquals(true, list.remove(3))
assertEquals(true, list.remove(5))
assertEquals("""
size: 2
elements: 2 - 4
""".trimIndent(), list.toString())
assertEquals(true, list.remove(2))
assertEquals(true, list.remove(4))
assertEquals(true, list.isEmpty)
list.add(6)
list.add(7)
list.add(11)
list.add(13)
assertEquals("""
size: 4
elements: 6 - 7 - 11 - 13
""".trimIndent(), list.toString())
list.clear()
assertEquals(true, list.isEmpty)
}
}
================================================
FILE: src/test/kotlin/structures/Stack1Test.kt
================================================
package structures
import org.junit.Test
import org.junit.Assert.assertEquals
class Stack1Test {
@Test
fun test() {
val stack = Stack1()
stack.push(1)
stack.push(2)
stack.push(3)
assertEquals(false, stack.isEmpty)
assertEquals(3, stack.size)
assertEquals(3, stack.pop())
assertEquals(2, stack.pop())
assertEquals(1, stack.pop())
assertEquals(true, stack.isEmpty)
assertEquals(0, stack.size)
stack.push(10)
stack.push(20)
stack.push(30)
assertEquals(3, stack.size)
assertEquals(30, stack.peek())
assertEquals(3, stack.size)
stack.clear()
assertEquals(true, stack.isEmpty)
assertEquals(0, stack.size)
}
}
================================================
FILE: src/test/kotlin/structures/Stack2Test.kt
================================================
package structures
import org.junit.Test
import org.junit.Assert.assertEquals
class Stack2Test {
@Test
fun test() {
val stack = Stack2()
stack.push(1)
stack.push(2)
stack.push(3)
assertEquals(false, stack.isEmpty)
assertEquals(3, stack.size)
assertEquals(3, stack.pop())
assertEquals(2, stack.pop())
assertEquals(1, stack.pop())
assertEquals(true, stack.isEmpty)
assertEquals(0, stack.size)
stack.push(10)
stack.push(20)
stack.push(30)
assertEquals(3, stack.size)
assertEquals(30, stack.peek())
assertEquals(3, stack.size)
stack.clear()
assertEquals(true, stack.isEmpty)
assertEquals(0, stack.size)
}
}