diff --git a/.gitignore b/.gitignore index 938d3f90..fb741484 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ highlights/node_modules highlights/atom-language-perl6/ .DS_store highlights/package-lock.json +zig-cache # IDE specific .scala_dependencies @@ -40,3 +41,14 @@ highlights/package-lock.json *.sublime-workspace /.env atlassian-ide-plugin.xml +.vscode + +# Python specific +__pycache__ +.ipynb_checkpoints/ + +# R specific +.Rproj.user +.Rhistory +.RData +.Ruserdata diff --git a/01_introduction_to_algorithms/1C/Module.bsl b/01_introduction_to_algorithms/1C/Module.bsl new file mode 100644 index 00000000..9f6f0542 --- /dev/null +++ b/01_introduction_to_algorithms/1C/Module.bsl @@ -0,0 +1,54 @@ + +#Область ОбработчикиКомандФормы + +&НаКлиенте +Процедура НайтиЧисло(Команда) + ИскомоеЧисло = 75; + Сообщение = Новый СообщениеПользователю; + + КоличествоПопыток = БинарныйПоиск(ИскомоеЧисло); + + Если КоличествоПопыток = Неопределено Тогда + ТекстСообщения = НСтр("ru = 'Число не входит в диапозон 1..100'"); + Иначе + ШаблонСообщения = НСтр("ru = 'Число %1 найдено за %2 попыток'"); + ТекстСообщения = СтрШаблон(ШаблонСообщения, ИскомоеЧисло, КоличествоПопыток); + КонецЕсли; + + Сообщение.Текст = ТекстСообщения; + Сообщение.Сообщить(); +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +&НаКлиенте +Функция БинарныйПоиск(ИскомоеЧисло) + + Массив = Новый Массив; + + Для Счетчик = 1 По 100 Цикл + Массив.Добавить(Счетчик); + КонецЦикла; + + КоличествоПопыток = 0; + МинимальноеЧисло = Массив[0]; + МаксимальноеЧисло = Массив[Массив.Количество() - 1]; + Пока МинимальноеЧисло <= МаксимальноеЧисло Цикл + КоличествоПопыток = КоличествоПопыток + 1; + НайденноеЧисло = Цел((МинимальноеЧисло + МаксимальноеЧисло) / 2); + Если НайденноеЧисло = ИскомоеЧисло Тогда + Возврат КоличествоПопыток; + ИначеЕсли НайденноеЧисло > ИскомоеЧисло Тогда + МаксимальноеЧисло = НайденноеЧисло - 1; + Иначе // НайденноеЧисло < ИскомоеЧисло + МинимальноеЧисло = НайденноеЧисло + 1; + КонецЕсли; + КонецЦикла; + + Возврат Неопределено; + +КонецФункции + +#КонецОбласти diff --git a/01_introduction_to_algorithms/ES6/01_binary_search.js b/01_introduction_to_algorithms/ES6/01_binary_search.js index 7b3e2183..83704d67 100644 --- a/01_introduction_to_algorithms/ES6/01_binary_search.js +++ b/01_introduction_to_algorithms/ES6/01_binary_search.js @@ -1,3 +1,9 @@ +/** + * Searches recursively number from the list + * @param {Array} list Source array + * @param {number} item Search item + * @returns {(number|null)} Number if the value is found or NULL otherwise + */ const binarySearch = (list, item) => { let low = 0; let high = list.length - 1; @@ -8,8 +14,7 @@ const binarySearch = (list, item) => { if (guess === item) { return mid; - } - if (guess > item) { + } else if (guess > item) { high = mid - 1; } else { low = mid + 1; diff --git a/01_introduction_to_algorithms/ES6/02_recursive_binary_search.js b/01_introduction_to_algorithms/ES6/02_recursive_binary_search.js index 9fb9e96b..fd96dada 100644 --- a/01_introduction_to_algorithms/ES6/02_recursive_binary_search.js +++ b/01_introduction_to_algorithms/ES6/02_recursive_binary_search.js @@ -1,41 +1,34 @@ /** * Searches recursively number from the list - * @param {Array} list + * @param {Array} list Source array * @param {number} item Search item * @param {number} low Lower limit of search in the list * @param {number} high Highest limit of search in the list - * @return {(number | null)} Number if the value is found or NULL otherwise + * @returns {(number|null)} Number if the value is found or NULL otherwise */ -const binarySearch = ( list, item, low = 0, high = list.length - 1 ) => { - let arrLength = list.length; - while ( low <= high ) { - let mid = Math.floor((low + high) / 2); - let guess = list[mid]; +const binarySearch = (list, item, low = 0, high = list.length - 1) => { + if (low > high) return null; - if ( guess === item ) { - return mid; - } else if ( guess > item ) { - high = mid - 1; - list = list.slice( 0, mid ); - return binarySearch( list, item, low, high ); - } else { - low = mid + 1; - list = list.slice( low, arrLength ); - return binarySearch( list, item, low, high ); - } - } + const mid = Math.floor((low + high) / 2); + const guess = list[mid]; - return null; + if (guess === item) { + return mid; + } else if (guess > item) { + return binarySearch(list, item, low, mid - 1); + } else { + return binarySearch(list, item, mid + 1, high); + } }; /** * Creates the array that contains numbers 1...N * @param {number} n - number N - * @return {Array} + * @returns {Array} Array that contains numbers 1...N */ -const createArr = ( n ) => Array.from({length: n}, (v, k) => k + 1); +const createArr = n => Array.from({ length: n }, (v, k) => k + 1); -const myList = createArr( 100 ); +const myList = createArr(100); -console.log( binarySearch( myList, 3 ) ); // 2 -console.log( binarySearch( myList, -1 ) ); // null +console.log(binarySearch(myList, 3)); // 2 +console.log(binarySearch(myList, -1)); // null diff --git a/01_introduction_to_algorithms/Golang/BinarySearch.go b/01_introduction_to_algorithms/Golang/BinarySearch.go index 04724d7d..d360d1aa 100644 --- a/01_introduction_to_algorithms/Golang/BinarySearch.go +++ b/01_introduction_to_algorithms/Golang/BinarySearch.go @@ -2,13 +2,13 @@ package main import "fmt" -func checkBin(list []int, i int) bool { +func checkBin(list []int, i int) int { low := 0 high := len(list) - 1 for low <= high { mid := (low + high) / 2 if list[mid] == i { - return true + return mid } if list[mid] < i { low = mid + 1 @@ -16,10 +16,29 @@ func checkBin(list []int, i int) bool { high = mid - 1 } } - return false + return -1 +} + +func RecursiveCheckBin(list []int, item int, high, low int) int { + if high >= low { + mid := (high + low) / 2 + + if list[mid] == item { + return mid + } else if list[mid] > item { + return RecursiveCheckBin(list, item, mid-1, low) + } else { + return RecursiveCheckBin(list, item, high, mid+1) + } + + } + return -1 } func main() { - fmt.Println(checkBin([]int{1, 2, 3, 4, 5}, 1)) // true - fmt.Println(checkBin([]int{1, 2, 3, 4, 5}, -1)) //false + list := []int{1, 2, 3, 4, 5} + fmt.Println(checkBin(list, 2)) // 0 + fmt.Println(checkBin(list, -1)) // -1 + fmt.Println(RecursiveCheckBin([]int{1, 2, 3, 4, 5}, 2, len(list)-1, 0)) // 1 + fmt.Println(RecursiveCheckBin([]int{1, 2, 3, 4, 5}, 0, len(list)-1, 0)) //-1 } diff --git a/01_introduction_to_algorithms/Purescript/BinarySearch.purs b/01_introduction_to_algorithms/Purescript/BinarySearch.purs new file mode 100644 index 00000000..81ed644f --- /dev/null +++ b/01_introduction_to_algorithms/Purescript/BinarySearch.purs @@ -0,0 +1,39 @@ +module GrokkingAlgos.BinarySearch where + +import Prelude +import Data.Array ((!!)) +import Data.Array as Array +import Data.Maybe (Maybe(..)) +import Effect (Effect) +import Effect.Class.Console (logShow) + +-- | Binary Search - input is a sorted list of elements +-- | Big o notation - log n +-- | Traveling salesman - O (n!) +binarysearch :: Int -> Array Int -> Int -> Int -> Maybe Int +binarysearch x arr low high + | low > high = Nothing + | otherwise = + let + mid = (high + low) / 2 + in + arr !! mid + >>= case _ of + item + | item == x -> Just mid + item + | item > x -> binarysearch x arr low (mid - 1) + item + | item < x -> binarysearch x arr (mid + 1) high + _ -> Nothing + +find :: Int -> Array Int -> Maybe Int +find x arr = binarysearch x arr low high + where + low = 0 + + high = (Array.length arr) - 1 + +main :: Effect Unit +main = do + logShow $ find 20 [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20 ] diff --git a/01_introduction_to_algorithms/Purescript/README.md b/01_introduction_to_algorithms/Purescript/README.md new file mode 100644 index 00000000..a4476480 --- /dev/null +++ b/01_introduction_to_algorithms/Purescript/README.md @@ -0,0 +1,6 @@ +# Getting Started +1. Install `spago` and `purescript` through `yarn` or `npm` (e.g. `yarn global add spago` and `yarn global add purescript`) +2. Run file through `spago run --watch --main ` (e.g. `spago run --watch --main GrokkingAlgos.SelectionSort`) + +# Main Repo +- https://github.com/seanyu4296/grokking-algo-in-purs \ No newline at end of file diff --git a/01_introduction_to_algorithms/Purescript/packages.dhall b/01_introduction_to_algorithms/Purescript/packages.dhall new file mode 100644 index 00000000..3ecb3c90 --- /dev/null +++ b/01_introduction_to_algorithms/Purescript/packages.dhall @@ -0,0 +1,8 @@ +let upstream = + https://github.com/purescript/package-sets/releases/download/psc-0.13.8-20200724/packages.dhall sha256:bb941d30820a49345a0e88937094d2b9983d939c9fd3a46969b85ce44953d7d9 + +let overrides = {=} + +let additions = {=} + +in upstream // overrides // additions diff --git a/01_introduction_to_algorithms/Purescript/spago.dhall b/01_introduction_to_algorithms/Purescript/spago.dhall new file mode 100644 index 00000000..721cd6d8 --- /dev/null +++ b/01_introduction_to_algorithms/Purescript/spago.dhall @@ -0,0 +1,9 @@ +{- +Welcome to a Spago project! +You can edit this file as you like. +-} +{ name = "my-project" +, dependencies = [ "console", "effect", "psci-support", "arrays", "debug", "lists", "ordered-collections", "strings"] +, packages = ./packages.dhall +, sources = [ "src/**/*.purs", "test/**/*.purs" ] +} diff --git a/01_introduction_to_algorithms/R/binary_search.R b/01_introduction_to_algorithms/R/binary_search.R new file mode 100644 index 00000000..7d914075 --- /dev/null +++ b/01_introduction_to_algorithms/R/binary_search.R @@ -0,0 +1,37 @@ +binary_search <- function(list, item) { + # low and high keep track of which part of the list you'll search in. + # Every data structure in R indexed by starting at 1. + low <- 1 + high <- length(list) + + # While you haven't narrowed it down to one element ... + while (low <= high) { + # ... check the middle element + mid <- (low + high) %/% 2 + guess <- list[mid] + # Found the item. + if (guess == item) { + return(mid) + } + # The guess was too high. + else if (guess > item) { + high <- mid - 1 + } + else{ # The guess was too low. + low <- mid + 1 + } + } + # Item doesn't exist + return(NULL) +} + + +# Set a list +my_list <- list(1, 3, 5, 7, 9) + +# Call the function +binary_search(my_list, 3) # => 1 +binary_search(my_list, -1) # => NULL + +# All above code can be simplified by using "which" function +which(my_list == 3) # => 1 diff --git a/01_introduction_to_algorithms/c++11/01_binary_search.cpp b/01_introduction_to_algorithms/c++11/01_binary_search.cpp index f0e06e51..b56f945f 100644 --- a/01_introduction_to_algorithms/c++11/01_binary_search.cpp +++ b/01_introduction_to_algorithms/c++11/01_binary_search.cpp @@ -5,7 +5,7 @@ using std::cout; using std::endl; template -int binary_search(const std::vector& list, const int& item) { +int binary_search(const std::vector& list, const T& item) { int low = 0; int high = list.size() - 1; diff --git a/01_introduction_to_algorithms/d/01_binary_search.d b/01_introduction_to_algorithms/d/01_binary_search.d new file mode 100644 index 00000000..7d9e1377 --- /dev/null +++ b/01_introduction_to_algorithms/d/01_binary_search.d @@ -0,0 +1,27 @@ +module app; + +import std.stdio: writeln; +import std.range: assumeSorted, SortedRange; + +long binary_search(T)(SortedRange!(T[]) list, T item) { + long low = 0; + long high = list.length - 1; + + while (low <= high) { + auto mid = (low + high) / 2; + T guess = list[mid]; + if (guess == item) + return mid; + else if (guess > item) + high = mid - 1; + else + low = mid + 1; + } + return -1; +} + +void main() { + auto my_list = [1, 3, 5, 7, 9]; + writeln(binary_search(assumeSorted(my_list), 3)); + writeln(binary_search(assumeSorted(my_list), -1)); +} diff --git a/01_introduction_to_algorithms/dart/binary_search.dart b/01_introduction_to_algorithms/dart/binary_search.dart new file mode 100644 index 00000000..62041392 --- /dev/null +++ b/01_introduction_to_algorithms/dart/binary_search.dart @@ -0,0 +1,26 @@ +void main() { + final myList = [1, 3, 5, 7, 9]; + print(binarySearch(myList, 3)); + print(binarySearch(myList, -1)); +} + +int? binarySearch(List list, int item) { + int low = 0; + int high = list.length - 1; + + while (low <= high) { + final mid = (low + high) ~/ 2; + final guess = list[mid]; + + if (guess == item) { + return mid; + } + + if (guess > item) { + high = mid - 1; + } else { + low = mid + 1; + } + } + return null; +} diff --git a/01_introduction_to_algorithms/f#/Program.fs b/01_introduction_to_algorithms/f#/Program.fs new file mode 100644 index 00000000..f081473c --- /dev/null +++ b/01_introduction_to_algorithms/f#/Program.fs @@ -0,0 +1,26 @@ +// Learn more about F# at http://fsharp.org + +open System + +[] +let main argv = + let numbers = [|1; 2; 3; 4; 5; 6; 7; 8; 9; 10|] + + let rec binarySearch(arr: int[], number: int, startIndex: int, endIndex: int) : int + = + let averageIndex = (startIndex + endIndex) / 2 + let middleElement = arr.[averageIndex] + + if (middleElement > number) + then binarySearch(arr, number, startIndex, averageIndex) + else if (middleElement < number) + then binarySearch(arr, number, averageIndex, endIndex) + else + averageIndex + + let binarySearch(arr: int[], number: int) + = binarySearch(arr, number, 0, arr.Length) + + let index = binarySearch(numbers, 7) + Console.WriteLine(index); + 0 diff --git a/01_introduction_to_algorithms/java/01_binary_search/src/main/BinarySearch.java b/01_introduction_to_algorithms/java/01_binary_search/src/main/BinarySearch.java new file mode 100644 index 00000000..bc3086d3 --- /dev/null +++ b/01_introduction_to_algorithms/java/01_binary_search/src/main/BinarySearch.java @@ -0,0 +1,63 @@ +package main; + +public class BinarySearch { + public static void main(String[] args) { + int[] myList = {87, 21, 45, 93}; + + System.out.println(binarySearch(myList, 93)); + System.out.println(binarySearch(myList, 16)); + } + + public static int binarySearch(int[] list, int item) { + if (isListEmpty(list)) { + return -1; + } + + int low = 0; + int high = list.length - 1; + + while (low <= high) { + int mid = (low + high) / 2; + int guess = list[mid]; + + if (guessEqualsItem(guess, item)) { + return mid; + } else if (guessGreaterThanItem(guess, item)) { + high = mid - 1; + } else if(guessLessThanItem(guess, item)) { + low = mid + 1; + } + } + + return -1; + } + + public static boolean isListEmpty(int[] myList) { + int listSize = myList.length; + if (listSize == 0) { + return true; + } + return false; + } + + public static boolean guessEqualsItem(int guess, int item) { + if (guess != item) { + return false; + } + return true; + } + + public static boolean guessGreaterThanItem(int guess, int item) { + if (guess < item) { + return false; + } + return true; + } + + public static boolean guessLessThanItem(int guess, int item) { + if (guess > item) { + return false; + } + return true; + } +} diff --git a/01_introduction_to_algorithms/java/01_binary_search/src/test/BinarySearchTest.java b/01_introduction_to_algorithms/java/01_binary_search/src/test/BinarySearchTest.java new file mode 100644 index 00000000..5ebc5e38 --- /dev/null +++ b/01_introduction_to_algorithms/java/01_binary_search/src/test/BinarySearchTest.java @@ -0,0 +1,50 @@ +package test; + +import main.BinarySearch; +import org.junit.Assert; +import org.junit.Test; + +public class BinarySearchTest { + @Test + public void testListIsEmpty() { + BinarySearch binarySearch = new BinarySearch(); + int[] myList = {6, 9}; + int[] emptyList = {}; + + Assert.assertEquals(false, binarySearch.isListEmpty(myList)); + Assert.assertEquals(true, binarySearch.isListEmpty(emptyList)); + } + + @Test + public void testGuessEqualsItem() { + BinarySearch binarySearch = new BinarySearch(); + + Assert.assertEquals(true, binarySearch.guessEqualsItem(3, 3)); + Assert.assertEquals(false, binarySearch.guessEqualsItem(0, 4)); + } + + @Test + public void testGuessIsLessThanItem() { + BinarySearch binarySearch = new BinarySearch(); + + Assert.assertEquals(true, binarySearch.guessLessThanItem(2, 7)); + Assert.assertEquals(false, binarySearch.guessLessThanItem(6, 1)); + } + + @Test + public void testGuessGreaterThanItem() { + BinarySearch binarySearch = new BinarySearch(); + + Assert.assertEquals(true, binarySearch.guessGreaterThanItem(17, 12)); + Assert.assertEquals(false, binarySearch.guessGreaterThanItem(13, 28)); + } + + @Test + public void testGivenListAndItemReturnIndexOfItem() { + BinarySearch binarySearch = new BinarySearch(); + int[] testList = {1, 3, 5, 7, 9}; + + Assert.assertEquals(1, binarySearch.binarySearch(testList, 3)); + Assert.assertEquals(-1, binarySearch.binarySearch(testList, 77)); + } +} diff --git a/01_introduction_to_algorithms/javascript/01_binary_search.js b/01_introduction_to_algorithms/javascript/01_binary_search.js index 1d5cc269..a9c27f4c 100644 --- a/01_introduction_to_algorithms/javascript/01_binary_search.js +++ b/01_introduction_to_algorithms/javascript/01_binary_search.js @@ -1,22 +1,28 @@ -'use strict'; +"use strict"; +/** + * Searches recursively number from the list + * @param {Array} list Source array + * @param {number} item Search item + * @returns {(number|null)} Number if the value is found or NULL otherwise + */ function binary_search(list, item) { let low = 0; let high = list.length - 1; - + while (low <= high) { - let mid = Math.floor((low + high) / 2); - let guess = list[mid]; -  if (guess === item) { + const mid = Math.floor((low + high) / 2); + const guess = list[mid]; + + if (guess === item) { return mid; - } - if (guess > item) { + } else if (guess > item) { high = mid - 1; } else { low = mid + 1; } } - + return null; } diff --git a/01_introduction_to_algorithms/julia/binary_search.jil b/01_introduction_to_algorithms/julia/01_binary_search.jl similarity index 100% rename from 01_introduction_to_algorithms/julia/binary_search.jil rename to 01_introduction_to_algorithms/julia/01_binary_search.jl diff --git a/01_introduction_to_algorithms/python/01_binary_search.py b/01_introduction_to_algorithms/python/01_binary_search.py deleted file mode 100644 index 35ed5cbe..00000000 --- a/01_introduction_to_algorithms/python/01_binary_search.py +++ /dev/null @@ -1,28 +0,0 @@ -def binary_search(list, item): - # low and high keep track of which part of the list you'll search in. - low = 0 - high = len(list) - 1 - - # While you haven't narrowed it down to one element ... - while low <= high: - # ... check the middle element - mid = (low + high) // 2 - guess = list[mid] - # Found the item. - if guess == item: - return mid - # The guess was too high. - if guess > item: - high = mid - 1 - # The guess was too low. - else: - low = mid + 1 - - # Item doesn't exist - return None - -my_list = [1, 3, 5, 7, 9] -print(binary_search(my_list, 3)) # => 1 - -# 'None' means nil in Python. We use to indicate that the item wasn't found. -print(binary_search(my_list, -1)) # => None diff --git a/01_introduction_to_algorithms/python/binary_search.py b/01_introduction_to_algorithms/python/binary_search.py new file mode 100644 index 00000000..4e3c10cd --- /dev/null +++ b/01_introduction_to_algorithms/python/binary_search.py @@ -0,0 +1,58 @@ +class BinarySearch(): + + def search_iterative(self, list, item): + # low and high keep track of which part of the list you'll search in. + low = 0 + high = len(list) - 1 + + # While you haven't narrowed it down to one element ... + while low <= high: + # ... check the middle element + mid = (low + high) // 2 + guess = list[mid] + # Found the item. + if guess == item: + return mid + # The guess was too high. + if guess > item: + high = mid - 1 + # The guess was too low. + else: + low = mid + 1 + + # Item doesn't exist + return None + + def search_recursive(self, list, low, high, item): + # Check base case + if high >= low: + + mid = (high + low) // 2 + guess = list[mid] + + # If element is present at the middle itself + if guess == item: + return mid + + # If element is smaller than mid, then it can only + # be present in left subarray + elif guess > item: + return self.search_recursive(list, low, mid - 1, item) + + # Else the element can only be present in right subarray + else: + return self.search_recursive(list, mid + 1, high, item) + + else: + # Element is not present in the array + return None + +if __name__ == "__main__": + # We must initialize the class to use the methods of this class + bs = BinarySearch() + my_list = [1, 3, 5, 7, 9] + + print(bs.search_iterative(my_list, 3)) # => 1 + + # 'None' means nil in Python. We use to indicate that the item wasn't found. + print(bs.search_iterative(my_list, -1)) # => None \ No newline at end of file diff --git a/01_introduction_to_algorithms/python/items.json b/01_introduction_to_algorithms/python/items.json new file mode 100644 index 00000000..bbff4dbd --- /dev/null +++ b/01_introduction_to_algorithms/python/items.json @@ -0,0 +1,6 @@ +{ + "simple_list": [2, 3, 4, 13, 40], + "list_with_10_items": [3, 9, 10, 11, 12, 13, 14, 17, 18, 19], + "list_with_100_items": [146, 161, 193, 217, 266, 276, 460, 487, 585, 756, 842, 889, 954, 985, 1061, 1114, 1169, 1256, 1509, 1533, 1680, 1829, 1917, 1995, 2013, 2085, 2134, 2182, 2249, 2261, 2306, 2499, 2543, 2723, 2731, 3196, 3253, 3271, 3351, 3514, 3557, 3629, 3755, 3884, 3935, 4163, 4236, 4296, 4298, 4420, 4661, 4764, 4901, 4912, 4943, 5043, 5224, 5247, 5444, 5485, 5569, 5742, 5778, 5862, 6064, 6096, 6122, 6425, 6455, 6472, 6493, 6656, 6764, 6778, 6946, 7126, 7165, 7208, 7211, 7283, 7407, 7584, 7675, 7827, 7992, 8155, 8309, 8439, 8482, 9180, 9198, 9292, 9335, 9383, 9509, 9537, 9631, 9727, 9780, 9795], + "list_with_1000_items": [7, 15, 18, 21, 32, 34, 37, 39, 45, 48, 55, 60, 65, 70, 86, 101, 112, 119, 120, 151, 152, 161, 170, 172, 200, 206, 223, 232, 233, 236, 270, 292, 300, 324, 333, 347, 354, 355, 363, 411, 419, 430, 443, 448, 457, 465, 497, 505, 508, 514, 526, 528, 534, 552, 555, 589, 597, 612, 627, 645, 654, 657, 663, 668, 670, 689, 692, 702, 703, 706, 726, 727, 732, 740, 743, 747, 756, 773, 777, 786, 787, 789, 794, 799, 801, 803, 842, 852, 856, 866, 901, 902, 904, 909, 912, 928, 929, 932, 939, 965, 984, 1006, 1019, 1045, 1050, 1078, 1080, 1094, 1103, 1105, 1119, 1121, 1132, 1137, 1145, 1166, 1169, 1174, 1183, 1188, 1194, 1199, 1202, 1223, 1227, 1237, 1241, 1255, 1265, 1279, 1290, 1291, 1310, 1315, 1317, 1324, 1326, 1342, 1350, 1362, 1363, 1366, 1371, 1376, 1392, 1393, 1395, 1399, 1406, 1415, 1429, 1446, 1448, 1453, 1466, 1469, 1471, 1480, 1500, 1518, 1520, 1521, 1529, 1548, 1558, 1560, 1561, 1565, 1569, 1573, 1593, 1597, 1599, 1616, 1618, 1645, 1646, 1693, 1694, 1713, 1714, 1717, 1734, 1740, 1742, 1763, 1780, 1806, 1814, 1823, 1828, 1844, 1849, 1853, 1860, 1867, 1869, 1870, 1882, 1889, 1895, 1904, 1908, 1934, 1951, 1980, 1991, 1993, 1996, 2005, 2021, 2028, 2033, 2038, 2044, 2047, 2053, 2054, 2061, 2067, 2087, 2091, 2096, 2101, 2119, 2128, 2132, 2133, 2136, 2160, 2175, 2186, 2201, 2202, 2207, 2209, 2211, 2219, 2222, 2240, 2278, 2288, 2322, 2327, 2339, 2342, 2360, 2367, 2386, 2392, 2394, 2405, 2409, 2416, 2436, 2443, 2476, 2478, 2491, 2493, 2494, 2496, 2524, 2525, 2541, 2557, 2562, 2584, 2618, 2623, 2625, 2627, 2637, 2661, 2674, 2678, 2692, 2703, 2704, 2711, 2715, 2716, 2722, 2730, 2766, 2781, 2786, 2802, 2835, 2836, 2857, 2859, 2873, 2878, 2880, 2923, 2948, 2975, 2980, 2994, 3003, 3009, 3013, 3019, 3020, 3043, 3050, 3056, 3073, 3074, 3078, 3083, 3084, 3093, 3100, 3102, 3112, 3121, 3145, 3153, 3159, 3187, 3202, 3247, 3250, 3264, 3283, 3284, 3288, 3290, 3292, 3299, 3301, 3326, 3333, 3338, 3341, 3361, 3377, 3389, 3393, 3401, 3435, 3454, 3456, 3467, 3474, 3482, 3485, 3490, 3491, 3498, 3504, 3530, 3534, 3545, 3552, 3564, 3574, 3586, 3606, 3615, 3619, 3622, 3636, 3647, 3655, 3688, 3711, 3725, 3739, 3760, 3765, 3774, 3780, 3791, 3822, 3826, 3828, 3830, 3841, 3849, 3854, 3857, 3863, 3885, 3888, 3889, 3903, 3911, 3916, 3961, 3981, 4045, 4080, 4082, 4089, 4122, 4134, 4145, 4151, 4152, 4176, 4193, 4200, 4205, 4211, 4213, 4215, 4227, 4237, 4238, 4249, 4257, 4275, 4281, 4294, 4297, 4299, 4310, 4316, 4326, 4328, 4338, 4341, 4357, 4359, 4363, 4364, 4396, 4414, 4435, 4437, 4442, 4470, 4471, 4484, 4486, 4489, 4493, 4512, 4515, 4524, 4527, 4543, 4550, 4553, 4555, 4560, 4568, 4571, 4587, 4600, 4613, 4627, 4633, 4668, 4673, 4676, 4686, 4691, 4710, 4719, 4731, 4767, 4775, 4780, 4803, 4815, 4831, 4834, 4879, 4882, 4914, 4918, 4922, 4925, 4941, 4954, 4967, 4981, 4982, 4985, 4993, 4999, 5013, 5026, 5033, 5038, 5044, 5052, 5055, 5066, 5086, 5089, 5098, 5103, 5118, 5146, 5147, 5148, 5164, 5177, 5180, 5190, 5196, 5201, 5217, 5221, 5263, 5271, 5278, 5280, 5286, 5295, 5316, 5319, 5320, 5344, 5371, 5376, 5380, 5384, 5391, 5406, 5415, 5436, 5439, 5446, 5451, 5465, 5474, 5485, 5504, 5507, 5511, 5519, 5522, 5544, 5548, 5567, 5572, 5591, 5595, 5618, 5619, 5621, 5627, 5635, 5659, 5678, 5682, 5690, 5703, 5714, 5716, 5719, 5721, 5742, 5760, 5771, 5774, 5786, 5827, 5843, 5845, 5853, 5871, 5874, 5877, 5878, 5887, 5900, 5904, 5923, 5925, 5945, 5967, 6004, 6005, 6006, 6009, 6027, 6038, 6047, 6053, 6057, 6061, 6067, 6075, 6079, 6080, 6088, 6089, 6106, 6113, 6145, 6151, 6155, 6165, 6171, 6179, 6182, 6192, 6198, 6207, 6220, 6232, 6234, 6240, 6243, 6252, 6258, 6270, 6274, 6286, 6300, 6301, 6314, 6316, 6322, 6325, 6326, 6339, 6349, 6354, 6365, 6371, 6384, 6387, 6402, 6412, 6430, 6436, 6447, 6452, 6463, 6464, 6467, 6480, 6487, 6539, 6559, 6565, 6566, 6567, 6572, 6581, 6588, 6592, 6604, 6614, 6623, 6640, 6642, 6648, 6649, 6653, 6682, 6694, 6710, 6733, 6748, 6761, 6769, 6774, 6779, 6780, 6781, 6793, 6846, 6861, 6880, 6898, 6922, 6930, 6938, 6949, 6964, 6977, 6983, 6993, 7001, 7009, 7010, 7015, 7019, 7023, 7025, 7028, 7033, 7049, 7051, 7060, 7076, 7080, 7114, 7118, 7119, 7129, 7131, 7134, 7137, 7168, 7169, 7183, 7219, 7242, 7257, 7258, 7299, 7301, 7304, 7306, 7310, 7317, 7318, 7322, 7326, 7337, 7346, 7358, 7382, 7388, 7389, 7390, 7392, 7398, 7400, 7415, 7423, 7425, 7427, 7429, 7444, 7450, 7475, 7486, 7490, 7491, 7499, 7526, 7532, 7536, 7549, 7562, 7570, 7578, 7579, 7583, 7597, 7600, 7605, 7626, 7628, 7630, 7636, 7639, 7645, 7648, 7661, 7680, 7681, 7694, 7706, 7717, 7723, 7732, 7734, 7738, 7740, 7762, 7773, 7802, 7829, 7846, 7847, 7878, 7903, 7915, 7922, 7926, 7932, 7938, 7960, 7967, 7975, 7985, 8002, 8013, 8031, 8039, 8040, 8046, 8071, 8073, 8075, 8082, 8098, 8099, 8105, 8139, 8148, 8159, 8165, 8171, 8187, 8188, 8197, 8204, 8220, 8222, 8226, 8247, 8248, 8263, 8267, 8274, 8283, 8299, 8301, 8315, 8361, 8370, 8372, 8373, 8395, 8396, 8400, 8406, 8421, 8427, 8437, 8447, 8456, 8458, 8467, 8470, 8474, 8506, 8513, 8514, 8522, 8525, 8542, 8543, 8544, 8562, 8570, 8577, 8580, 8586, 8590, 8602, 8607, 8614, 8624, 8630, 8634, 8650, 8666, 8667, 8671, 8677, 8688, 8699, 8713, 8723, 8724, 8733, 8734, 8736, 8742, 8744, 8746, 8749, 8764, 8774, 8786, 8803, 8807, 8849, 8853, 8861, 8865, 8869, 8875, 8882, 8900, 8904, 8905, 8916, 8919, 8947, 8965, 8969, 8981, 8988, 8997, 9004, 9019, 9028, 9037, 9044, 9071, 9074, 9076, 9079, 9152, 9163, 9164, 9166, 9182, 9199, 9227, 9230, 9238, 9247, 9258, 9269, 9290, 9307, 9314, 9351, 9361, 9362, 9367, 9376, 9382, 9395, 9412, 9426, 9430, 9434, 9439, 9453, 9465, 9474, 9481, 9491, 9494, 9502, 9504, 9524, 9539, 9542, 9550, 9573, 9579, 9596, 9600, 9632, 9633, 9641, 9663, 9674, 9684, 9693, 9697, 9700, 9706, 9708, 9710, 9713, 9716, 9747, 9751, 9753, 9767, 9772, 9773, 9775, 9776, 9783, 9788, 9789, 9805, 9808, 9819, 9822, 9827, 9833, 9838, 9840, 9847, 9852, 9857, 9866, 9874, 9881, 9887, 9901, 9917, 9931, 9945, 9949, 9952, 9991, 9997, 9999] +} \ No newline at end of file diff --git a/01_introduction_to_algorithms/python/test_binary_search.py b/01_introduction_to_algorithms/python/test_binary_search.py new file mode 100644 index 00000000..490e05d0 --- /dev/null +++ b/01_introduction_to_algorithms/python/test_binary_search.py @@ -0,0 +1,107 @@ +from binary_search import BinarySearch +import unittest +import json +import time + +bs = BinarySearch() + +# Unloading all lists from a file +with open("items.json", "r") as file: + data = json.load(file) + +# Setting values to created variables +simple_list = data["simple_list"] +list_with_10_items = data["list_with_10_items"] +list_with_100_items = data["list_with_100_items"] +list_with_1000_items = data["list_with_1000_items"] + + +# Test cases to test Binary Search algorithm +class TestBinarySearch(unittest.TestCase): + + def setUp(self): + print (".......... %s" % self._testMethodName) + + # Checking the implementation of iterative binary search + def test_iterative_binary_search_with_simple_list(self): + # ARRANGE + # You can check the index of each item in the items.json file + item, expected_index = 3, 1 + + # ACT + # Run the method we created and get the index of the item we were looking for + index = bs.search_iterative(simple_list, item) # => 1 + + # ASSERT + # Compare the resulting index with the expected index + self.assertEqual(expected_index, index) # => 1 == 1 + + def test_recoursive_binary_search_with_simple_list(self): + item, expected_index = 3, 1 + # To run recursive search for an item, + # we need to determine the minimum and maximum indexes of the list + low, high = 0, len(simple_list) - 1 + + index = bs.search_recursive(simple_list, low, high, item) + + self.assertEqual(expected_index, index) + + def test_search_for_nonexistent_item(self): + # Specifically set a number that is not in the list + item, expected_result = 100, None + + # Trying to find an item that doesn't exist + index = bs.search_iterative(simple_list, item) # => None + + self.assertEqual(expected_result, index) + + def test_binary_search_and_linear_search_execution_time(self): + item, expected_index = 9887, 990 + + # Time required to search + start_time = time.time() + binary_search_index = bs.search_iterative(list_with_1000_items, item) # => None + bs_time = time.time() - start_time + + # list.index(x) return the index in the list of the first item whose value is x. + # It is an error if there is no such item. + # Complexity of list.index(x) is O(n) + start_time = time.time() + linear_search_index = list_with_1000_items.index(item) + ls_time = time.time() - start_time + + self.assertEqual(expected_index, binary_search_index) + self.assertEqual(expected_index, linear_search_index) + self.assertTrue(bs_time < ls_time) + + # print("--- Time required to search item at the ending ---") + # print("--- Linear Search %f seconds ---" % (ls_time)) + # print("--- Binary Search %f seconds ---" % (bs_time)) + + def test_execution_time_for_item_at_the_beginning(self): + item, expected_index = 55, 10 + + # Binary search - time required to search + start_time = time.time() + binary_search_index = bs.search_iterative(list_with_1000_items, item) # => None + bs_time = time.time() - start_time + + # Linear search - time required to search + start_time = time.time() + linear_search_index = list_with_1000_items.index(item) + ls_time = time.time() - start_time + + self.assertEqual(expected_index, binary_search_index) + self.assertEqual(expected_index, linear_search_index) + + # linear search will be faster, since the item we are looking for + # is at the beginning of the list + self.assertTrue(bs_time > ls_time) + + # print("--- Time required to search item at the beginning ---") + # print("--- Linear Search %f seconds ---" % (ls_time)) + # print("--- Binary Search %f seconds ---" % (bs_time)) + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/01_introduction_to_algorithms/ruby/02_recursive_binary_search.rb b/01_introduction_to_algorithms/ruby/02_recursive_binary_search.rb new file mode 100644 index 00000000..f2fff1bc --- /dev/null +++ b/01_introduction_to_algorithms/ruby/02_recursive_binary_search.rb @@ -0,0 +1,26 @@ +def binary_search(list, item, low = 0, high = list.length - 1) + while low <= high + mid = (low + high) / 2 + guess = list[mid] + + if guess == item + return mid + elsif guess > item + high = mid - 1 + binary_search(list, item, low, high) + else + low = mid + 1 + binary_search(list, item, low, high) + end + end + + # If item is not found + return nil +end + +# Create array with numbers 1 through 100 +my_list = (1..100).to_a + +puts binary_search(my_list, 2) # => 1 +puts binary_search(my_list, 50) # => 49 +p binary_search(my_list, 101) # => nil diff --git a/01_introduction_to_algorithms/rust/main_example_1.rs b/01_introduction_to_algorithms/rust/main_example_1.rs new file mode 100644 index 00000000..f45ce144 --- /dev/null +++ b/01_introduction_to_algorithms/rust/main_example_1.rs @@ -0,0 +1,108 @@ +// name = "binary-search" +// version = "0.1.0" +// authors = ["giorgiodelgado "] +// + +// to run tests, you must have rust and cargo installed +// then run `cargo test` + +use std::cmp; + +// assumes that the slice is already sorted +fn binary_search(lst: &[T], item: T) -> Option { + let mid = ((lst.len() / 2) as f32).ceil() as usize; + + match lst.get(mid) { + None => None, + Some(val) => { + if *val == item { + Some(mid) + } else if *val > item { + let sublist = &lst[..mid]; + binary_search(sublist, item) + } else { + let sublist = &lst[(mid + 1)..]; + // mapping is necessary when the item is + // to the right of the middle since indices on the + // sublist are erased and being at 0, 1, 2, 3, ... etc + binary_search(sublist, item).map(|pos| pos + mid + 1) + } + }, + } +} + +fn main() { + let num_slice = &[2, 4, 5, 12, 15, 30, 32, 33, 34, 40, 45, 51, 55, 57, 60, 66, 70, 71, 90, 99, 100]; + + let result = binary_search(num_slice, 70); + + println!("Result: {:?}", result); +} + + +#[cfg(test)] +mod test { + use super::binary_search; + + #[test] + fn finds_number_near_end_of_list() { + let num_slice = &[2, 4, 5, 12, 15, 30, 32, 33, 34, 40, 45, 51, 55, 57, 60, 66, 70, 71, 90, 99, 100]; + + assert_eq!(binary_search(num_slice, 70), Some(16)); + } + + #[test] + fn finds_number_near_start_of_list() { + let num_slice = &[2, 4, 5, 12, 15, 30, 32, 33, 34, 40, 45, 51, 55, 57, 60, 66, 70, 71, 90, 99, 100]; + + assert_eq!(binary_search(num_slice, 5), Some(2)); + } + + #[test] + fn returns_none_for_numbers() { + let num_slice = &[2, 4, 5, 12, 15, 30, 32, 33, 34, 40, 45, 51, 55, 57, 60, 66, 70, 71, 90, 99, 100]; + + assert_eq!(binary_search(num_slice, 1), None); + } + + #[test] + fn finds_char() { + let char_slice = &[ + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + ]; + + assert_eq!(binary_search(char_slice, 'l'), Some(11)); + } + + #[test] + fn returns_none_for_chars() { + let char_slice = &['a', 'b', 'c']; + + assert_eq!(binary_search(char_slice, 'l'), None); + } +} diff --git a/01_introduction_to_algorithms/scheme/01_binarysearch.scm b/01_introduction_to_algorithms/scheme/01_binarysearch.scm new file mode 100644 index 00000000..66525103 --- /dev/null +++ b/01_introduction_to_algorithms/scheme/01_binarysearch.scm @@ -0,0 +1,14 @@ +(define (binary-search my-list item) + (iter my-list item 0 (- (length my-list) 1))) + +(define (iter my-list item low high) + (if (> low high) 'nill + (let* ((mid (floor (/ (+ low high) 2))) + (guess (list-ref my-list mid))) + (cond ((eqv? guess item) mid) + ((> guess item) (iter my-list item low (- mid 1))) + (else (iter my-list item (+ mid 1) high)))))) + + +(display (binary-search (list 1 3 5 7 9) 3)) ;; 1 +(display (binary-search (list 1 3 5 7 9) -1)) ;; nill diff --git a/01_introduction_to_algorithms/swift/01_binary_search.swift b/01_introduction_to_algorithms/swift/01_binary_search.swift index 232c5525..91a0c9e8 100644 --- a/01_introduction_to_algorithms/swift/01_binary_search.swift +++ b/01_introduction_to_algorithms/swift/01_binary_search.swift @@ -8,7 +8,7 @@ func binarySearch (_ list: [T], item: T) -> Int? { // While you haven't narrowed it down to one element ... while low <= high { //... check the middle element - let mid = low + (high - low) / 2 + let mid = (low + high) / 2 let guess = list[mid] // Found the item. if guess == item { diff --git a/01_introduction_to_algorithms/zig/binary-search.zig b/01_introduction_to_algorithms/zig/binary-search.zig new file mode 100644 index 00000000..56513143 --- /dev/null +++ b/01_introduction_to_algorithms/zig/binary-search.zig @@ -0,0 +1,37 @@ +const std = @import("std"); +const print = std.debug.print; +const expect = std.testing.expect; + +pub fn main() void { + const my_list = &[_]i8{ 1, 3, 5, 7, 9 }; + + print("{?}\n", .{binarySearch(i8, my_list, 3)}); + print("{?}\n", .{binarySearch(i8, my_list, -1)}); +} + +fn binarySearch(comptime T: type, list: []const T, item: T) ?usize { + var low: i32 = 0; + const u_high: u32 = @truncate(list.len); + var high: i32 = @intCast(u_high - 1); + + return while (low <= high) { + const mid = @divTrunc((low + high), 2); + const m: usize = @intCast(mid); + const guess = list[m]; + if (guess == item) break m; + if (guess > item) { + high = mid - 1; + } else low = mid + 1; + } else null; +} + +test "binarySearch" { + const my_list = &[_]i8{ 1, 3, 5, 7, 9 }; + + var i = binarySearch(i8, my_list, 3); + try expect(i != null); + try expect(i.? == 1); + + i = binarySearch(i8, my_list, -1); + try expect(i == null); +} diff --git a/02_selection_sort/ES6/01_selection_sort.js b/02_selection_sort/ES6/01_selection_sort.js index 31b6a8cb..ec7861b4 100644 --- a/02_selection_sort/ES6/01_selection_sort.js +++ b/02_selection_sort/ES6/01_selection_sort.js @@ -1,8 +1,8 @@ -// Selection Sort - O(log n^2) -// Parameter: -// 1. random array - -// 1. Finds the smallest value in an array +/** + * Finds the index of the element with the smallest value in the array + * @param {Array} array Source array + * @returns {number} Index of the element with the smallest value + */ const findSmallestIndex = (array) => { let smallestElement = array[0]; // Stores the smallest value let smallestIndex = 0; // Stores the index of the smallest value @@ -17,19 +17,27 @@ const findSmallestIndex = (array) => { return smallestIndex; }; -// 2. Sorts the array +/** + * Sort array by increment + * @param {Array} array Source array + * @returns {Array} New sorted array + */ const selectionSort = (array) => { const sortedArray = []; - const length = array.length; + const copyArray = [...array]; - for (let i = 0; i < length; i++) { - // Finds the smallest element in the given array - const smallestIndex = findSmallestIndex(array); + for (let i = 0; i < array.length; i++) { + // Finds the smallest element in the array + const smallestIndex = findSmallestIndex(copyArray); // Adds the smallest element to new array - sortedArray.push(array.splice(smallestIndex, 1)[0]); + sortedArray.push(copyArray.splice(smallestIndex, 1)[0]); } return sortedArray; }; -console.log(selectionSort([5, 3, 6, 2, 10])); // [2, 3, 5, 6, 10] +const sourceArray = [5, 3, 6, 2, 10]; +const sourtedArray = selectionSort([5, 3, 6, 2, 10]); + +console.log("Source array - ", sourceArray); // [5, 3, 6, 2, 10] +console.log("New sorted array - ", sourtedArray); // [2, 3, 5, 6, 10] diff --git a/02_selection_sort/ES6/02_recursive_selection_sort.js b/02_selection_sort/ES6/02_recursive_selection_sort.js new file mode 100644 index 00000000..116674ff --- /dev/null +++ b/02_selection_sort/ES6/02_recursive_selection_sort.js @@ -0,0 +1,36 @@ +/** + * Finds the index of the element with the smallest value in the array + * @param {Array} array Source array + * @returns {number} Index of the element with the smallest value + */ +const findSmallestIndex = array => { + let smallestElement = array[0]; // Stores the smallest value + let smallestIndex = 0; // Stores the index of the smallest value + + for (let i = 1; i < array.length; i++) { + if (array[i] < smallestElement) { + smallestElement = array[i]; + smallestIndex = i; + } + } + + return smallestIndex; +}; + +/** + * Sort array by increment + * @param {Array} array Source array + * @returns {Array} New sorted array + */ +const selectionSort = array => { + if (!array.length) return []; + const copyArray = [...array]; + const smallest = copyArray.splice(findSmallestIndex(copyArray), 1); + return smallest.concat(selectionSort(copyArray)); +}; + +const sourceArray = [5, 3, 6, 2, 10]; +const sourtedArray = selectionSort([5, 3, 6, 2, 10]); + +console.log("Source array - ", sourceArray); // [5, 3, 6, 2, 10] +console.log("New sorted array - ", sourtedArray); // [2, 3, 5, 6, 10] diff --git a/02_selection_sort/Purescript/README.md b/02_selection_sort/Purescript/README.md new file mode 100644 index 00000000..a4476480 --- /dev/null +++ b/02_selection_sort/Purescript/README.md @@ -0,0 +1,6 @@ +# Getting Started +1. Install `spago` and `purescript` through `yarn` or `npm` (e.g. `yarn global add spago` and `yarn global add purescript`) +2. Run file through `spago run --watch --main ` (e.g. `spago run --watch --main GrokkingAlgos.SelectionSort`) + +# Main Repo +- https://github.com/seanyu4296/grokking-algo-in-purs \ No newline at end of file diff --git a/02_selection_sort/Purescript/SelectionSort.purs b/02_selection_sort/Purescript/SelectionSort.purs new file mode 100644 index 00000000..6b55aff0 --- /dev/null +++ b/02_selection_sort/Purescript/SelectionSort.purs @@ -0,0 +1,17 @@ +module GrokkingAlgos.SelectionSort where + +import Prelude +import Data.Foldable (minimum) +import Data.List (List(..), delete, (:)) +import Data.Maybe (Maybe(..)) +import Effect (Effect) +import Effect.Class.Console (logShow) + +selectionsort :: List Int -> List Int +selectionsort l = case minimum l of + Nothing -> Nil + Just min -> min : selectionsort (delete min l) + +main :: Effect Unit +main = do + logShow $ selectionsort $ 1 : 2 : 3 : 5 : 4 : Nil diff --git a/02_selection_sort/Purescript/packages.dhall b/02_selection_sort/Purescript/packages.dhall new file mode 100644 index 00000000..3ecb3c90 --- /dev/null +++ b/02_selection_sort/Purescript/packages.dhall @@ -0,0 +1,8 @@ +let upstream = + https://github.com/purescript/package-sets/releases/download/psc-0.13.8-20200724/packages.dhall sha256:bb941d30820a49345a0e88937094d2b9983d939c9fd3a46969b85ce44953d7d9 + +let overrides = {=} + +let additions = {=} + +in upstream // overrides // additions diff --git a/02_selection_sort/Purescript/spago.dhall b/02_selection_sort/Purescript/spago.dhall new file mode 100644 index 00000000..721cd6d8 --- /dev/null +++ b/02_selection_sort/Purescript/spago.dhall @@ -0,0 +1,9 @@ +{- +Welcome to a Spago project! +You can edit this file as you like. +-} +{ name = "my-project" +, dependencies = [ "console", "effect", "psci-support", "arrays", "debug", "lists", "ordered-collections", "strings"] +, packages = ./packages.dhall +, sources = [ "src/**/*.purs", "test/**/*.purs" ] +} diff --git a/02_selection_sort/R/01_selection_sort.R b/02_selection_sort/R/01_selection_sort.R new file mode 100644 index 00000000..47741b4e --- /dev/null +++ b/02_selection_sort/R/01_selection_sort.R @@ -0,0 +1,30 @@ +# Finds the smallest value in an array +find_smallest <- function(arr) { + # Stores the smallest value + smallest = arr[1] + # Stores the index of the smallest value + smallest_index = 1 + for (i in 1:length(arr)) { + if (arr[i] < smallest) { + smallest_index = i + smallest = arr[i] + } + } + return(smallest_index) +} + +# Sort array +selection_sort <- function(arr) { + newArr = c() + for (i in 1:length(arr)) { + # Finds the smallest element in the array and adds it to the new array + smallest = find_smallest(arr) + newArr = c(newArr, arr[smallest]) + # Removes that smallest element from the original array + arr = arr[-smallest] + } + return(newArr) +} + +print(selection_sort(c(5, 3, 6, 2, 10))) + \ No newline at end of file diff --git a/02_selection_sort/c/01_selection_sort.c b/02_selection_sort/c/01_selection_sort.c index c0a511ee..169e3e5c 100644 --- a/02_selection_sort/c/01_selection_sort.c +++ b/02_selection_sort/c/01_selection_sort.c @@ -1,5 +1,6 @@ #include #include +#include #define SIZE 5 // Finds the smallest value in an array @@ -37,4 +38,4 @@ int main(void) { printf("%d ", sortarr[i]); } return 0; -} \ No newline at end of file +} diff --git a/02_selection_sort/csharp/01_selection_sort/Program.cs b/02_selection_sort/csharp/01_selection_sort/Program.cs index 4b5a1bd0..77d0a09a 100644 --- a/02_selection_sort/csharp/01_selection_sort/Program.cs +++ b/02_selection_sort/csharp/01_selection_sort/Program.cs @@ -37,5 +37,24 @@ private static int FindSmallest(List arr) } return smallestIndex; } + + public static int[] SelectionSort(int[] unorderedArray) + { + for (var i = 0; i < unorderedArray.Length; i++) + { + var smallestIndex = i; + + for (var remainingIndex = i + 1; remainingIndex < unorderedArray.Length; remainingIndex++) + { + if (unorderedArray[remainingIndex] < unorderedArray[smallestIndex]) + { + smallestIndex = remainingIndex; + } + } + (unorderedArray[i], unorderedArray[smallestIndex]) = (unorderedArray[smallestIndex], unorderedArray[i]); + } + + return unorderedArray; + } } -} +} \ No newline at end of file diff --git a/02_selection_sort/csharp/double_selection_sort/Program.cs b/02_selection_sort/csharp/double_selection_sort/Program.cs new file mode 100644 index 00000000..153bb06a --- /dev/null +++ b/02_selection_sort/csharp/double_selection_sort/Program.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace SelectionSort +{ + class Program + { + static void Main(string[] args) + { + var numbers = new int[] { 4, 5, 1, 3, 10, 9, 6, 8, 7, 2 }; + var sortedArr = SelectionSort(numbers); + + Console.WriteLine(string.Join(',', sortedArr)); + } + + private static int[] SelectionSort(int[] array) + => SelectionSort(new LinkedList(array)).ToArray(); + + private static IEnumerable SelectionSort(LinkedList list) + { + var minList = new LinkedList(); + var maxList = new LinkedList(); + + while (list.Count != 0) + { + var min = list.Min(); + list.Remove(min); + minList.AddLast(min); + + var max = list.Max(); + list.Remove(max); + maxList.AddFirst(max); + } + + return minList.Union(maxList); + } + } +} diff --git a/02_selection_sort/d/01_selection_sort.d b/02_selection_sort/d/01_selection_sort.d new file mode 100644 index 00000000..53d81bb3 --- /dev/null +++ b/02_selection_sort/d/01_selection_sort.d @@ -0,0 +1,32 @@ +module app; + +import std.stdio: writeln; +import std.algorithm: minIndex, remove; + + +// or it is possible to use minIndex +T findSmallest(T)(T[] arr) { + auto smallest = arr[0]; + auto smallest_index = 0; + foreach(i; 0 .. cast(int)arr.length) { + if (arr[i] < smallest) { + smallest = arr[i]; + smallest_index = i; + } + } + return smallest_index; +} + +T[] selectionSort(T)(T[] arr) { + T[] newArr = []; + foreach(i; 0 .. cast(int)arr.length) { + auto smallest = findSmallest(arr); // or use minIndex(arr); + newArr ~= arr[smallest]; + arr = arr.remove(smallest); + } + return newArr; +} + +void main() { + writeln(selectionSort([5, 3, 6, 2, 10])); +} diff --git a/02_selection_sort/dart/selection_sort.dart b/02_selection_sort/dart/selection_sort.dart new file mode 100644 index 00000000..4fd7553f --- /dev/null +++ b/02_selection_sort/dart/selection_sort.dart @@ -0,0 +1,29 @@ +main() { + print(selectionSort([5, 3, 6, 2, 10])); +} + +List selectionSort(List arr) { + final List newArr = List.empty(growable: true); + final arrLength = arr.length; + + for (int i = 0; i < arrLength; i++) { + final smallest = findSmallest(arr); + newArr.add(arr.removeAt(smallest)); + } + + return newArr; +} + +int findSmallest(List arr) { + int smallest = arr[0]; + int smallestIndex = 0; + + for (int i = 1; i < arr.length; i++) { + if (arr[i] < smallest) { + smallest = arr[i]; + smallestIndex = i; + } + } + + return smallestIndex; +} diff --git a/02_selection_sort/java/src/SelectionSort2.java b/02_selection_sort/java/src/SelectionSort2.java index 8228d899..9c389997 100644 --- a/02_selection_sort/java/src/SelectionSort2.java +++ b/02_selection_sort/java/src/SelectionSort2.java @@ -3,45 +3,21 @@ public class SelectionSort2 { // this version uses raw arrays instead of ArrayList - private static int[] selectionSort(int[] arr) { - int[] newArr = new int[arr.length]; - - for (int i = 0; i < newArr.length; i++) { - int smallestIndex = findSmallest(arr); - newArr[i] = arr[smallestIndex]; - - arr = getNewArrWithoutSmallest(arr, smallestIndex); - } - - return newArr; - } - - private static int[] getNewArrWithoutSmallest(int[] arr, int smallestIndex) { - int[] newArrWithoutSmallest = new int[arr.length - 1]; - for (int i = 0; i < arr.length; i++) { - if (i < smallestIndex) { - newArrWithoutSmallest[i] = arr[i]; - } else if (i > smallestIndex) { - newArrWithoutSmallest[i - 1] = arr[i]; - } - } - return newArrWithoutSmallest; - } - - private static int findSmallest(int[] arr) { - int smallest = arr[0]; - int smallestIndex = 0; - for (int i = 0; i < arr.length; i++) { - if (arr[i] < smallest) { - smallest = arr[i]; - smallestIndex = i; + public static void selectionSort(int[] arr) { + for (int i = 0; i < arr.length-1; i++) { + for (int j = i+1; j < arr.length; j++) { + if (arr[j] < arr[i]) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } } } - return smallestIndex; } public static void main(String[] args) { int[] arr = {5, 3, 6, 2, 10}; - System.out.println(Arrays.toString(selectionSort(arr))); // [2, 3, 5, 6, 10] + selectionSort(arr); + System.out.println(Arrays.toString(arr)); // [2, 3, 5, 6, 10] } } diff --git a/02_selection_sort/javascript/01_selection_sort.js b/02_selection_sort/javascript/01_selection_sort.js index 9fce20d1..b1e37c6c 100644 --- a/02_selection_sort/javascript/01_selection_sort.js +++ b/02_selection_sort/javascript/01_selection_sort.js @@ -1,36 +1,39 @@ 'use strict'; -// Selection Sort - O(n^2) -// Parameter: -// 1. random array - -// 1. Finds the smallest value in an array -function findSmallestIndex(array) { - var smallestElement = array[0]; // Stores the smallest value - var smallestIndex = 0; // Stores the index of the smallest value - - for (var i = 1; i < array.length; i++) { - if (array[i] < smallestElement) { - smallestElement = array[i]; - smallestIndex = i; - } +/** + * Finds the index of the element with the smallest value in the array + * @param {Array} array Source array + * @returns {number} Index of the element with the smallest value + */ +const findSmallest = (arr) => { + let [smallestElement] = arr; + let smallestIndex = 0; + for (let i = 1; i < arr.length; i++) { + const el = arr[i]; + if (el >= smallestElement) continue; + smallestElement = el; + smallestIndex = i; } - return smallestIndex; -} - -// 2. Sort the array -function selectionSort(array) { - var sortedArray = []; - var length = array.length; +}; - for (var i = 0; i < length; i++) { - // Finds the smallest element in the array - var smallestIndex = findSmallestIndex(array); - // Adds the smallest element to new array - sortedArray.push(array.splice(smallestIndex, 1)[0]); +/** + * Sort array by increment + * @param {Array} array Source array + * @returns {Array} New sorted array + */ +const selectionSort = (arr) => { + const size = arr.length; + const result = new Array(size).fill(0); + for (let i = 0; i < size; i++) { + const smallestIndex = findSmallest(arr); + const [smallestElement] = arr.splice(smallestIndex, 1); + result[i] = smallestElement; } + return result; +}; - return sortedArray; -} +const sourceArray = [5, 3, 6, 2, 10]; +const sortedArray = selectionSort(sourceArray); -console.log(selectionSort([5, 3, 6, 2, 10])); // [2, 3, 5, 6, 10] +console.log('Source array - ', sourceArray); // [5, 3, 6, 2, 10] +console.log('New sorted array - ', sortedArray); // [2, 3, 5, 6, 10] diff --git a/02_selection_sort/javascript/02_recursive_selection_sort.js b/02_selection_sort/javascript/02_recursive_selection_sort.js index 70f4f06b..276e7308 100644 --- a/02_selection_sort/javascript/02_recursive_selection_sort.js +++ b/02_selection_sort/javascript/02_recursive_selection_sort.js @@ -1,33 +1,33 @@ +'use strict'; /** * Finds smallest element of an aray * @param {Array} arr array for searching * @return {number} index of the smallest element in array */ -const findSmallest = ( arr ) => { - let smallest = arr[0]; - let smallestIndex = 0; - let arrLen = arr.length; - - for ( let i = 0; i < arrLen; i++ ) { - if ( arr[i] < smallest ) { - smallest = arr[i]; - smallestIndex = i; - } - } - return smallestIndex; +const findSmallest = (arr, smallest = arr[0], smallestIndex = 0, i = 1) => { + if (arr.length <= i) return smallestIndex; + const curr = arr[i]; + if (curr < smallest) { + smallest = curr; + smallestIndex = i; + } + return findSmallest(arr, smallest, smallestIndex, i + 1); }; /** - * Sorts0 recursively an array of numbers + * Sorts recursively an array of numbers * @param {Array} arr An array of numbers * @return {Array} New sorted array */ -const selectionSort = ( arr ) => { - if ( !arr.length ) return []; - let smallest = arr.splice( findSmallest( arr ), 1 ); - return smallest.concat( selectionSort( arr ) ); +const selectionSort = (arr, result = []) => { + if (arr.length > 0) { + const smallestIndex = findSmallest(arr); + const [smallest] = arr.splice(smallestIndex, 1); + result.push(smallest); + return selectionSort(arr, result); + } + return result; }; -let arr = [5, 3, 6, 2, 10]; - -console.log( selectionSort(arr) ); +const arr = [5, 3, 6, 2, 10]; +console.log(selectionSort(arr)); diff --git a/02_selection_sort/julia/01_selection_sort.jl b/02_selection_sort/julia/01_selection_sort.jl new file mode 100644 index 00000000..2aeb51f6 --- /dev/null +++ b/02_selection_sort/julia/01_selection_sort.jl @@ -0,0 +1,26 @@ +using Test + +function find_smallest(arr) + smallest = arr[1] + smallest_index = 1 + for i = 1:length(arr) + if arr[i] < smallest + smallest = arr[i] + smallest_index = i + end + end + return smallest_index +end + +function selection_sort(arr) + new_arr = Array{Int64}(undef,0) + for i = 1:length(arr) + smallest = find_smallest(arr) + append!(new_arr,arr[smallest]) + deleteat!(arr,smallest) + end + return new_arr +end + +arr = [5,3,6,2,10] +@test selection_sort(arr) == [2,3,5,6,10] diff --git a/02_selection_sort/rust/01_selection_sort/.gitignore b/02_selection_sort/rust/01_selection_sort/.gitignore new file mode 100644 index 00000000..50c83018 --- /dev/null +++ b/02_selection_sort/rust/01_selection_sort/.gitignore @@ -0,0 +1,10 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk \ No newline at end of file diff --git a/02_selection_sort/rust/01_selection_sort/Cargo.toml b/02_selection_sort/rust/01_selection_sort/Cargo.toml new file mode 100644 index 00000000..673ae940 --- /dev/null +++ b/02_selection_sort/rust/01_selection_sort/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "selection-sort" +version = "0.1.0" +authors = ["Alexander Launi "] +edition = "2018" + +[dependencies] diff --git a/02_selection_sort/rust/01_selection_sort/src/main.rs b/02_selection_sort/rust/01_selection_sort/src/main.rs new file mode 100644 index 00000000..2272dd06 --- /dev/null +++ b/02_selection_sort/rust/01_selection_sort/src/main.rs @@ -0,0 +1,68 @@ +// Swaps elements in an array +fn swap(list: &mut [T], index_a: usize, index_b: usize) { + let tmp = list[index_a]; + list[index_a] = list[index_b]; + list[index_b] = tmp; +} + +fn selection_sort(list: &mut [T]) { + for i in 0..list.len() { + for j in (i+1)..list.len() { + if list[j] > list[i] { + swap(list, i, j); + } + } + } +} + +fn main() { + let list = &mut [156, 141, 35, 94, 88, 61, 111]; + print!("{:?} => ", list); + selection_sort(list); + print!("{:?}\n", list); +} + +#[cfg(test)] +mod test { + use super::selection_sort; + + #[test] + fn sort_unsigned_list() { + let mut list : [u8; 7] = [156, 141, 35, 94, 88, 61, 111]; + let list_sorted : [u8; 7] = [156, 141, 111, 94, 88, 61, 35]; + selection_sort(&mut list); + + assert_eq!(list, list_sorted); + } + + #[test] + fn sort_signed_list() { + let mut list : [i32; 10] = [75, 85, -26, 61, 20, -40, -72, 30, -27, 58]; + let list_sorted : [i32; 10] = [85, 75, 61, 58, 30, 20, -26, -27, -40, -72]; + selection_sort(&mut list); + + assert_eq!(list, list_sorted); + } + + #[test] + fn sort_strings() { + let mut list : [&str; 7] = ["Radiohead", "Kishore Kumar", "The Black Keys", + "Neutral Milk Hotel", "Beck", "The Strokes", "Wilco" + ]; + let list_sorted : [&str; 7] = ["Wilco", "The Strokes", "The Black Keys", + "Radiohead", "Neutral Milk Hotel", "Kishore Kumar", "Beck" + ]; + selection_sort(&mut list); + + assert_eq!(list, list_sorted); + } + + #[test] + fn sorts_an_empty_list() { + let mut list : [u8; 0] = []; + let list_sorted : [u8; 0] = []; + selection_sort(&mut list); + + assert_eq!(list, list_sorted); + } +} \ No newline at end of file diff --git a/02_selection_sort/scheme/01_selection_sort.scm b/02_selection_sort/scheme/01_selection_sort.scm new file mode 100644 index 00000000..e6d3e723 --- /dev/null +++ b/02_selection_sort/scheme/01_selection_sort.scm @@ -0,0 +1,37 @@ +(define (find-smallest my-list) + (let ((smallest (list-ref my-list 0)) + (smallest-i 0) + (i 0) + (last-index (- (length my-list) 1))) + (iter-find my-list smallest-i smallest i last-index))) + +(define (iter-find my-list smallest-i smallest i last-index) + (if (> i last-index) + smallest-i + (let ((my-list-i (list-ref my-list i))) + (if (< my-list-i smallest) + (iter-find my-list i my-list-i (+ i 1) last-index) + (iter-find my-list smallest-i smallest (+ i 1) last-index))))) + + +(define (selection-sort my-list) + (let* ((my-list-length (length my-list)) + (result (list)) + (i 0) + (last-i (- my-list-length 1))) + (iter-sort my-list i last-i result))) + +(define (iter-sort my-list i last-i result) + (if (> i last-i) + result + (let* ((smallest-i (find-smallest my-list)) + (smallest (list-ref my-list smallest-i)) + (filtered-list (filter (lambda (n) (not (= n smallest))) + my-list)) + (new-result (append result (list smallest)))) + (iter-sort filtered-list (+ i 1) last-i new-result)))) + + +(display (selection-sort (list 1 3 5 7 9))) ;; #(1 3 5 7 9) +(display (selection-sort (list 9 7 5 3 1))) ;; #(1 3 5 7 9) +(display (selection-sort (list 9 5 7 1 3))) ;; #(1 3 5 7 9) diff --git a/02_selection_sort/swift/01_selection_sort.swift b/02_selection_sort/swift/01_selection_sort.swift index df6edc74..e34f805f 100644 --- a/02_selection_sort/swift/01_selection_sort.swift +++ b/02_selection_sort/swift/01_selection_sort.swift @@ -4,13 +4,9 @@ import Foundation func findSmallestIndex (_ arr: [T]) -> Int { // Stores the smallest value var smallest = arr[0] - // We don't need any calculation if the array length is 1 - if arr.count == 1 { - return 0 - } // Stores the index of the smallest value var smallestIndex = 0 - for i in 1...arr.count-1 { + for i in 1.. (_ arr: [T]) -> Int { // Sort array func selectionSort (arr: [T]) -> [T] { + // We don't need any calculation if the array length is 1 + guard arr.count > 1 else { return arr } + var newArr: [T] = [] + // We have to make mutableArray reference copy of original array, because Swift 3 doesn't allow to get var parameter var mutableArr = arr - for _ in 0...mutableArr.count-1 { + for _ in 0.. list[j]) { + // swap + const tmp = list[i]; + list[i] = list[j]; + list[j] = tmp; + } + } + } +} + +test "selectionSort" { + var s = [_]i32{ 5, 3, 6, 2, 10 }; + const exp = [_]i32{ 2, 3, 5, 6, 10 }; + + selectionSort(i32, s[0..]); + + try expect(s.len == exp.len); + for (s, 0..) |e, i| + try expect(e == exp[i]); +} diff --git a/03_recursion/ES6/01_countdown.js b/03_recursion/ES6/01_countdown.js index 46418877..b9a22f65 100644 --- a/03_recursion/ES6/01_countdown.js +++ b/03_recursion/ES6/01_countdown.js @@ -1,10 +1,11 @@ +/** + * Countdown + * @param {number} i Number + */ const countdown = i => { console.log(i); // base case - if (i <= 0) { - return; - } - + if (i <= 0) return; countdown(i - 1); }; diff --git a/03_recursion/ES6/02_greet.js b/03_recursion/ES6/02_greet.js index ffec6692..b6587430 100644 --- a/03_recursion/ES6/02_greet.js +++ b/03_recursion/ES6/02_greet.js @@ -1,12 +1,23 @@ +/** + * Displays a message to the console + * @param {string} name Name + */ const greet2 = name => console.log(`how are you, ${name}?`); -const bye = () => console.log('ok bye!'); +/** + * Displays a message to the console + */ +const bye = () => console.log("ok bye!"); -const greet = (name) => { +/** + * Displays a message to the console + * @param {string} name Name + */ +const greet = name => { console.log(`hello, ${name}!`); greet2(name); - console.log('getting ready to say bye...'); + console.log("getting ready to say bye..."); bye(); }; -greet('adit'); +greet("adit"); diff --git a/03_recursion/ES6/03_factorial.js b/03_recursion/ES6/03_factorial.js index 022a61df..5a2a469d 100644 --- a/03_recursion/ES6/03_factorial.js +++ b/03_recursion/ES6/03_factorial.js @@ -1,7 +1,10 @@ -const fact = (x) => { - if (x === 1) { - return 1; - } +/** + * Consider the factorial of the number + * @param {number} x Number + * @returns {number} Result + */ +const fact = x => { + if (x === 0) return 1; return x * fact(x - 1); }; diff --git a/03_recursion/Golang/03_factorial/Factorial.go b/03_recursion/Golang/03_factorial/Factorial.go index 5a0a6e1c..24214021 100644 --- a/03_recursion/Golang/03_factorial/Factorial.go +++ b/03_recursion/Golang/03_factorial/Factorial.go @@ -3,7 +3,7 @@ package main import "fmt" func fact(x int) int { - if x == 1 { + if x == 0 { return 1 } diff --git a/03_recursion/c++11/02_greet.cpp b/03_recursion/c++11/02_greet.cpp index c743a898..9af462f4 100644 --- a/03_recursion/c++11/02_greet.cpp +++ b/03_recursion/c++11/02_greet.cpp @@ -17,6 +17,7 @@ void greet(std::string name) { cout << "Hello, " + name + "!" << endl; greet2(name); cout << "Getting ready to say bye..." << endl; + bye(); } diff --git a/03_recursion/d/01_countdown.d b/03_recursion/d/01_countdown.d new file mode 100644 index 00000000..6662a763 --- /dev/null +++ b/03_recursion/d/01_countdown.d @@ -0,0 +1,18 @@ +module app; + +import std; + +void countdown(int i) { + // base case + if (i <= 0) + return 0; + // recursive case + else { + writeln(i); + return countdown(i-1); + } +} + +void main() { + countdown(5); +} diff --git a/03_recursion/d/02_greet.d b/03_recursion/d/02_greet.d new file mode 100644 index 00000000..e1d58653 --- /dev/null +++ b/03_recursion/d/02_greet.d @@ -0,0 +1,22 @@ +module app; + +import std; + +void greet2(string name) { + writeln(i"how are you $(name)?"); +} + +void bye() { + writeln("ok bye!"); +} + +void greet(string name) { + writeln(i"hello, #(name)!"); + greet2(name); + writeln("gettin ready to say bye..."); + bye(); +} + +void main() { + greet("adit"); +} diff --git a/03_recursion/d/03_factorial.d b/03_recursion/d/03_factorial.d new file mode 100644 index 00000000..aa360c58 --- /dev/null +++ b/03_recursion/d/03_factorial.d @@ -0,0 +1,14 @@ +module app; + +import std; + +T fact(T x) { + if (x == 1) + return 1; + else + return x * fact(x-1); +} + +void main() { + writeln(fact(5)); +} diff --git a/03_recursion/d/04_count.d b/03_recursion/d/04_count.d new file mode 100644 index 00000000..65ce37f7 --- /dev/null +++ b/03_recursion/d/04_count.d @@ -0,0 +1,9 @@ +module app; + +import std; + +int count(T[] arr) { + if (arr.empty) + return 0; + return 1 + count(arr[1..$]); +} diff --git a/03_recursion/d/05_binary_search_recursive.d b/03_recursion/d/05_binary_search_recursive.d new file mode 100644 index 00000000..261b2e6d --- /dev/null +++ b/03_recursion/d/05_binary_search_recursive.d @@ -0,0 +1,23 @@ +module app; + +import std; + +int binary_search(T)(T[] arr, T target) { + if (arr.length == 0) + return -1; + + int mid = cast(int)arr.length / 2; + if (arr[mid] == target) + return mid; + else if (arr[mid] > target) + return binary_search(arr[0..mid], target); + else { + int recursive_response = binary_search(arr[mid + 1 .. $], target); + return recursive_response == -1 ? recursive_response : (mid + 1) + recursive_response; + } +} + +void main() { + writeln(binary_search([6, 7, 8, 9, 10], 8)); + writeln(binary_search([6, 7, 8, 9, 10], 6)); +} diff --git a/03_recursion/d/06_find_max.d b/03_recursion/d/06_find_max.d new file mode 100644 index 00000000..d09a1459 --- /dev/null +++ b/03_recursion/d/06_find_max.d @@ -0,0 +1,10 @@ +T find_max(T)(T[] arr) { + if (arr.length == 0) + return 0; + else if (arr.length == 1) + return arr[0]; + else if (arr.length == 2) + return arr[0] > arr[1] ? arr[0] : arr[1]; + auto sub_max = find_max(arr[1..$]); + return arr[0] > sub_max ? arr[0] : sub_max; +} diff --git a/03_recursion/d/07_sum_array.d b/03_recursion/d/07_sum_array.d new file mode 100644 index 00000000..22e5e344 --- /dev/null +++ b/03_recursion/d/07_sum_array.d @@ -0,0 +1,5 @@ +T sum_array(T)(T[] arr) { + if (arr.empty) + return 0; + return arr[0] + sum_array(arr[1..$]); +} diff --git a/03_recursion/d/08_look_for_key.d b/03_recursion/d/08_look_for_key.d new file mode 100644 index 00000000..68c7ecb4 --- /dev/null +++ b/03_recursion/d/08_look_for_key.d @@ -0,0 +1,61 @@ +modeul app; + +import std; + +class Item { + bool is_key = false; + Item[] items_in_box; + + this() { + this.is_key = false; + } + + this(bool key) { + this.is_key = key; + } + + bool is_a_box() { + return !this.is_key; + } + + bool is_a_key() { + return this.is_key; + } +} + +void look_for_key(Item box) { + foreach(item; box.items_in_box) + if (item.is_a_box()) + // recursive case + look_for_key(item); + else if (item.is_a_key()) + // base case + writeln("found the key!"); +} + +/* +main_box +├── box_A +│ ├── box_B +│ └── box_C +└── box_D + └── box_E + └── key +*/ +void main() { + auto main_box = new Item(); + auto box_A = new Item(); + auto box_B = new Item(); + auto box_C = new Item(); + box_A.items_in_box = [box_B, box_C]; + + auto box_D = new Item(); + auto box_E = new Item(); + auto key = new Item(true); + box_E.items_in_box = [key]; + box_D.items_in_box = [box_E]; + + main_box.items_in_box = [box_A, box_D]; + + look_for_key(main_box); +} diff --git a/03_recursion/dart/01_countdown/countdown.dart b/03_recursion/dart/01_countdown/countdown.dart new file mode 100644 index 00000000..9c93f39d --- /dev/null +++ b/03_recursion/dart/01_countdown/countdown.dart @@ -0,0 +1,14 @@ +main() { + final Stopwatch stopwatch = Stopwatch()..start(); + print(recursiveCount([0, 21, 3, 1, 6, 5, 81, 2, 14, 56, 32, 1, 9, 8])); + stopwatch.stop(); + print(stopwatch.elapsedMilliseconds); +} + +int recursiveCount(List array) { + if (array.isEmpty) { + return 0; + } + final List newArray = [...array]..removeAt(0); + return 1 + recursiveCount(newArray); +} diff --git a/03_recursion/dart/02_sum/sum.dart b/03_recursion/dart/02_sum/sum.dart new file mode 100644 index 00000000..b1d4c8a3 --- /dev/null +++ b/03_recursion/dart/02_sum/sum.dart @@ -0,0 +1,14 @@ +void main(List args) { + final Stopwatch stopwatch = Stopwatch()..start(); + print(recursiveSum([0, 21, 3, 1, 6, 5, 81, 2, 14, 56, 32, 1, 9, 8])); + stopwatch.stop(); + print(stopwatch.elapsedMilliseconds); +} + +int recursiveSum(List array) { + if (array.isEmpty) { + return 0; + } + final List newArray = [...array]..removeAt(0); + return array[0] + recursiveSum(newArray); +} diff --git a/03_recursion/dart/03_factorial/factorial.dart b/03_recursion/dart/03_factorial/factorial.dart new file mode 100644 index 00000000..b6bce640 --- /dev/null +++ b/03_recursion/dart/03_factorial/factorial.dart @@ -0,0 +1,13 @@ +void main(List args) { + final Stopwatch stopwatch = Stopwatch()..start(); + print(recursiveFactorial(5)); + stopwatch.stop(); + print(stopwatch.elapsedMilliseconds); +} + +int recursiveFactorial(int value) { + if (value == 1) { + return 1; + } + return value * recursiveFactorial(value - 1); +} diff --git a/03_recursion/java/03_factorial/src/Factorial2.java b/03_recursion/java/03_factorial/src/Factorial2.java new file mode 100644 index 00000000..c9bafcb2 --- /dev/null +++ b/03_recursion/java/03_factorial/src/Factorial2.java @@ -0,0 +1,21 @@ +public class Factorial2 { + public static void main(String[] args) { + Factorial2 factorial2 = new Factorial2(); + System.out.println("The factorial of 5 is " + factorial2.getFactorial(5)); + } + + public int getFactorial(int number) { + if (isZeroOrOne(number)) { + return 1; + } + + return number * getFactorial(number - 1); + } + + public boolean isZeroOrOne(int number) { + if (number > 1) { + return false; + } + return true; + } +} diff --git a/03_recursion/java/03_factorial/src/Factorial2Test.java b/03_recursion/java/03_factorial/src/Factorial2Test.java new file mode 100644 index 00000000..a5fdd4e6 --- /dev/null +++ b/03_recursion/java/03_factorial/src/Factorial2Test.java @@ -0,0 +1,20 @@ +import org.junit.Assert; +import org.junit.Test; + +public class Factorial2Test { + @Test + public void testIsZeroOrOne() { + Factorial2 factorial2 = new Factorial2(); + + Assert.assertEquals(true, factorial2.isZeroOrOne(0)); + Assert.assertEquals(true, factorial2.isZeroOrOne(1)); + Assert.assertEquals(false, factorial2.isZeroOrOne(5)); + } + + @Test + public void testFactorial() { + Factorial2 factorial2 = new Factorial2(); + + Assert.assertEquals(120, factorial2.getFactorial(5)); + } +} diff --git a/03_recursion/java/04_sum/src/Sum.java b/03_recursion/java/04_sum/src/Sum.java new file mode 100644 index 00000000..0abcb2da --- /dev/null +++ b/03_recursion/java/04_sum/src/Sum.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class Sum { + public static int sum(ArrayList num_list, int index) { + + if (num_list.size() == index) { + return 0; + } else { + int num = num_list.get(index); + return num + sum(num_list, index + 1); + } + + } + + public static void main(String[] args) { + int total = sum(new ArrayList(Arrays.asList(2, 4, 6)), 0); + System.out.println(total); + } +} diff --git a/03_recursion/javascript/01_countdown.js b/03_recursion/javascript/01_countdown.js index 529d1c89..e4208c96 100644 --- a/03_recursion/javascript/01_countdown.js +++ b/03_recursion/javascript/01_countdown.js @@ -1,10 +1,11 @@ +/** + * Countdown + * @param {number} i Number + */ function countdown(i) { console.log(i); // base case - if (i <= 0) { - return; - } - + if (i <= 0) return; countdown(i - 1); } diff --git a/03_recursion/javascript/02_greet.js b/03_recursion/javascript/02_greet.js index 5161a086..54ec5fda 100644 --- a/03_recursion/javascript/02_greet.js +++ b/03_recursion/javascript/02_greet.js @@ -1,16 +1,27 @@ +/** + * Displays a message to the console + * @param {string} name Name + */ function greet2(name) { - console.log('how are you, ' + name + '?'); + console.log("how are you, " + name + "?"); } +/** + * Displays a message to the console + */ function bye() { - console.log('ok bye!'); + console.log("ok bye!"); } +/** + * Displays a message to the console + * @param {string} name Name + */ function greet(name) { - console.log('hello, ' + name + '!'); + console.log("hello, " + name + "!"); greet2(name); - console.log('getting ready to say bye...'); + console.log("getting ready to say bye..."); bye(); } -greet('adit'); +greet("adit"); diff --git a/03_recursion/javascript/03_factorial.js b/03_recursion/javascript/03_factorial.js index 89b8ab72..20d50a33 100644 --- a/03_recursion/javascript/03_factorial.js +++ b/03_recursion/javascript/03_factorial.js @@ -1,7 +1,10 @@ +/** + * Consider the factorial of the number + * @param {number} x Number + * @returns {number} Result + */ function fact(x) { - if (x === 1) { - return 1; - } + if (x === 0) return 1; return x * fact(x - 1); } diff --git a/03_recursion/julia/01_countdown.jl b/03_recursion/julia/01_countdown.jl new file mode 100644 index 00000000..2d47ceb2 --- /dev/null +++ b/03_recursion/julia/01_countdown.jl @@ -0,0 +1,24 @@ +using Test +using Suppressor + +function countdown(i) + println(i) + if i <= 0 + return + end + countdown(i-1) +end + +result = @capture_out(countdown(10)) # return stdout result +@test result == "10 +9 +8 +7 +6 +5 +4 +3 +2 +1 +0 +" diff --git a/03_recursion/julia/02_greet.jl b/03_recursion/julia/02_greet.jl new file mode 100644 index 00000000..3d607da7 --- /dev/null +++ b/03_recursion/julia/02_greet.jl @@ -0,0 +1,24 @@ +using Test +using Suppressor + +function greet2(name) + println("how are you, ",name,"?") +end + +function bye() + println("ok bye!") +end + +function greet(name) + println("hello, ",name,"!") + greet2(name) + println("getting ready to say bye...") + bye() +end + +result = @capture_out greet("adit") +@test result == "hello, adit! +how are you, adit? +getting ready to say bye... +ok bye! +" diff --git a/03_recursion/julia/03_factorial.jl b/03_recursion/julia/03_factorial.jl new file mode 100644 index 00000000..96675b03 --- /dev/null +++ b/03_recursion/julia/03_factorial.jl @@ -0,0 +1,10 @@ +using Test + +function factorial(x) + if x == 1 + return 1 + end + return x * factorial(x-1) +end + +@test factorial(5) == 120 diff --git a/03_recursion/python/04_count.py b/03_recursion/python/04_count.py new file mode 100644 index 00000000..418fdc7f --- /dev/null +++ b/03_recursion/python/04_count.py @@ -0,0 +1,4 @@ +def count(arr): + if not arr: + return 0 + return 1 + count(arr[1:]) \ No newline at end of file diff --git a/03_recursion/python/05_binary_search_recursive.py b/03_recursion/python/05_binary_search_recursive.py new file mode 100644 index 00000000..c6461d6b --- /dev/null +++ b/03_recursion/python/05_binary_search_recursive.py @@ -0,0 +1,21 @@ +def binary_search(arr, target): + if len(arr) == 0: + return None + + mid = len(arr) // 2 + + if arr[mid] == target: + return mid + elif arr[mid] > target: + return binary_search(arr[:mid], target) + else: + recursive_response = binary_search(arr[(mid + 1) :], target) + return ( + (mid + 1) + recursive_response + if recursive_response is not None + else recursive_response + ) + + +print(binary_search([6, 7, 8, 9, 10], 8)) +print(binary_search([6, 7, 8, 9, 10], 6)) diff --git a/03_recursion/python/06_find_max.py b/03_recursion/python/06_find_max.py new file mode 100644 index 00000000..bb5afc54 --- /dev/null +++ b/03_recursion/python/06_find_max.py @@ -0,0 +1,9 @@ +def find_max(arr): + if len(arr) == 0: + return 0 + elif len(arr) == 1: + return arr[0] + elif len(arr) == 2: + return arr[0] if arr[0] > arr[1] else arr[1] + sub_max = find_max(arr[1:]) + return arr[0] if arr[0] > sub_max else sub_max diff --git a/03_recursion/python/07_sum_array.py b/03_recursion/python/07_sum_array.py new file mode 100644 index 00000000..d71a0f28 --- /dev/null +++ b/03_recursion/python/07_sum_array.py @@ -0,0 +1,4 @@ +def sum_array(arr): + if not arr: + return 0 + return arr[0] + sum_array(arr[1:]) \ No newline at end of file diff --git a/03_recursion/python/08_look_for_key.py b/03_recursion/python/08_look_for_key.py new file mode 100644 index 00000000..8367b899 --- /dev/null +++ b/03_recursion/python/08_look_for_key.py @@ -0,0 +1,50 @@ +# Item have 2 types: key or box +class Item: + def __init__(self, is_key=False): + self.is_key = is_key + + # If not a key, it's a box that can hold items + self.items_in_box = [] + + def is_a_box(self): + return not self.is_key + + def is_a_key(self): + return self.is_key + + +def look_for_key(box: Item): + for item in box.items_in_box: + if item.is_a_box(): + # recursive case + look_for_key(item) + elif item.is_a_key(): + # base case + print("found the key!") + + +""" +main_box +├── box_A +│ ├── box_B +│ └── box_C +└── box_D + └── box_E + └── key +""" +main_box = Item() + +box_A = Item() +box_B = Item() +box_C = Item() +box_A.items_in_box = [box_B, box_C] + +box_D = Item() +box_E = Item() +key = Item(is_key = True) +box_E.items_in_box = [key] +box_D.items_in_box = [box_E] + +main_box.items_in_box = [box_A, box_D] + +look_for_key(main_box) \ No newline at end of file diff --git a/03_recursion/rust/01_countdown/.gitignore b/03_recursion/rust/01_countdown/.gitignore new file mode 100644 index 00000000..088ba6ba --- /dev/null +++ b/03_recursion/rust/01_countdown/.gitignore @@ -0,0 +1,10 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/03_recursion/rust/01_countdown/Cargo.toml b/03_recursion/rust/01_countdown/Cargo.toml new file mode 100644 index 00000000..9d582e32 --- /dev/null +++ b/03_recursion/rust/01_countdown/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "countdown" +version = "0.1.0" +authors = ["Alexander Launi "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +num-traits = "0.2" \ No newline at end of file diff --git a/03_recursion/rust/01_countdown/src/main.rs b/03_recursion/rust/01_countdown/src/main.rs new file mode 100644 index 00000000..84ae0e76 --- /dev/null +++ b/03_recursion/rust/01_countdown/src/main.rs @@ -0,0 +1,17 @@ +use std::ops::Sub; +use std::fmt::Display; +use num_traits::identities::One; +use num_traits::identities::Zero; + +fn countdown>(i: T) { + println!("{}", i); + if i.is_zero() { + return + } + + countdown(i - T::one()); +} + +fn main() { + countdown(5); +} diff --git a/03_recursion/rust/02_countdown/main.rs b/03_recursion/rust/02_countdown/main.rs new file mode 100644 index 00000000..9d6ddbe4 --- /dev/null +++ b/03_recursion/rust/02_countdown/main.rs @@ -0,0 +1,52 @@ +// Rust has three kinds of loops: loop, while, and for. Let’s try each one + recursive. +fn main() { + countdown_loop(5); + println!("------"); + + countdown_while(5); + println!("------"); + + countdown_for(5); + println!("------"); + + countdown_recursive(5); +} + + +fn countdown_loop(count: usize) { + let mut i = count; + + loop { + println!("{}", i); + i -= 1; + + if i <= 0 { + break; + } + } +} + +fn countdown_while(count: usize) { + let mut i = count; + + while i > 0 { + println!("{}", i); + + i -= 1; + } +} + + +fn countdown_for(count: usize) { + for i in (1..count + 1).rev() { + println!("{}", i); + } +} + +fn countdown_recursive(count: usize) { + println!("{}", count); + + if count > 1 { + return countdown_recursive(count - 1); + } +} diff --git a/03_recursion/rust/02_greet/.gitignore b/03_recursion/rust/02_greet/.gitignore new file mode 100644 index 00000000..088ba6ba --- /dev/null +++ b/03_recursion/rust/02_greet/.gitignore @@ -0,0 +1,10 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/03_recursion/rust/02_greet/Cargo.toml b/03_recursion/rust/02_greet/Cargo.toml new file mode 100644 index 00000000..98268b0c --- /dev/null +++ b/03_recursion/rust/02_greet/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "greet" +version = "0.1.0" +authors = ["Alexander Launi "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/03_recursion/rust/02_greet/src/main.rs b/03_recursion/rust/02_greet/src/main.rs new file mode 100644 index 00000000..8f90eb07 --- /dev/null +++ b/03_recursion/rust/02_greet/src/main.rs @@ -0,0 +1,18 @@ +fn greet2(name: &str) { + println!("how are you {}?", name); +} + +fn bye() { + println!("ok bye!"); +} + +fn greet(name: &str) { + println!("hello {}!", name); + greet2(name); + println!("getting ready to say bye..."); + bye(); +} + +fn main() { + greet("adit"); +} diff --git a/03_recursion/rust/03_factorial/.gitignore b/03_recursion/rust/03_factorial/.gitignore new file mode 100644 index 00000000..088ba6ba --- /dev/null +++ b/03_recursion/rust/03_factorial/.gitignore @@ -0,0 +1,10 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/03_recursion/rust/03_factorial/Cargo.toml b/03_recursion/rust/03_factorial/Cargo.toml new file mode 100644 index 00000000..223a6ece --- /dev/null +++ b/03_recursion/rust/03_factorial/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "factorial" +version = "0.1.0" +authors = ["Alexander Launi "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +num-traits = "0.2" diff --git a/03_recursion/rust/03_factorial/src/main.rs b/03_recursion/rust/03_factorial/src/main.rs new file mode 100644 index 00000000..3c774651 --- /dev/null +++ b/03_recursion/rust/03_factorial/src/main.rs @@ -0,0 +1,17 @@ +use std::ops::Sub; +use std::fmt::Display; +use num_traits::identities::One; + +fn fact + Copy + Display>(x: T) -> T { + if x < T::one() { + panic!("Invalid number: {}", x); + } else if x.is_one() { + return T::one(); + } + + return x * fact(x - T::one()); +} + +fn main() { + println!("{}", fact(3)); +} \ No newline at end of file diff --git a/03_recursion/zig/01_countdown.zig b/03_recursion/zig/01_countdown.zig new file mode 100644 index 00000000..43fd2eee --- /dev/null +++ b/03_recursion/zig/01_countdown.zig @@ -0,0 +1,13 @@ +const print = @import("std").debug.print; + +fn countdown(comptime T: type, i: T) void { + print("{} ", .{i}); + if (i <= 0) { + print("\n", .{}); + return; + } else countdown(T, i - 1); +} + +pub fn main() void { + countdown(u32, 5); +} diff --git a/03_recursion/zig/02_greet.zig b/03_recursion/zig/02_greet.zig new file mode 100644 index 00000000..19b403d9 --- /dev/null +++ b/03_recursion/zig/02_greet.zig @@ -0,0 +1,20 @@ +const print = @import("std").debug.print; + +pub fn main() void { + greet("adit"); +} + +fn bye() void { + print("ok bye!\n", .{}); +} + +fn greet(name: []const u8) void { + print("hello, {s}!\n", .{name}); + greet2(name); + print("getting ready to say bye...\n", .{}); + bye(); +} + +fn greet2(name: []const u8) void { + print("how are you, {s}?\n", .{name}); +} diff --git a/03_recursion/zig/03_factorial.zig b/03_recursion/zig/03_factorial.zig new file mode 100644 index 00000000..6e015cbf --- /dev/null +++ b/03_recursion/zig/03_factorial.zig @@ -0,0 +1,11 @@ +const print = @import("std").debug.print; + +fn fact(comptime T: type, x: T) T { + if (x == 1) { + return x; + } else return x * fact(T, x - 1); +} + +pub fn main() void { + print("{}\n", .{fact(i32, 5)}); +} diff --git a/03_recursion/zig/04_count.zig b/03_recursion/zig/04_count.zig new file mode 100644 index 00000000..487bb67e --- /dev/null +++ b/03_recursion/zig/04_count.zig @@ -0,0 +1,40 @@ +const print = @import("std").debug.print; +const expect = @import("std").testing.expect; + +pub fn main() void { + var arr = [_]i32{ 4, 3, 2, 1 }; + print("{}\n", .{count(i32, arr[0..])}); +} + +fn count(comptime T: type, arr: []T) T { + if (arr.len == 0) { + return 0; + } else return 1 + count(T, arr[1..]); +} + +test "count" { + var arr0 = [_]i32{}; + var arr1 = [_]i32{42}; + var arr2 = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + const tests = [_]struct { + arr: []i32, + exp: i32, + }{ + .{ + .arr = &arr0, + .exp = 0, + }, + .{ + .arr = &arr1, + .exp = 1, + }, + .{ + .arr = &arr2, + .exp = 9, + }, + }; + + for (tests) |t| { + try expect(count(@TypeOf(t.exp), t.arr) == t.exp); + } +} diff --git a/03_recursion/zig/05_binary_search_recursive.zig b/03_recursion/zig/05_binary_search_recursive.zig new file mode 100644 index 00000000..99e521d3 --- /dev/null +++ b/03_recursion/zig/05_binary_search_recursive.zig @@ -0,0 +1,59 @@ +const print = @import("std").debug.print; +const expect = @import("std").testing.expect; + +pub fn main() void { + print("{}\n", .{binarySearch(i32, &[_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 2)}); +} + +fn binarySearch(comptime T: type, arr: []const T, target: T) bool { + switch (arr.len) { + 0 => return false, + 1 => return arr[0] == target, + else => { + const mid = arr.len / 2; + if (arr[mid] > target) { + return binarySearch(T, arr[0..mid], target); + } else { + return binarySearch(T, arr[mid..], target); + } + }, + } +} + +test "binary search recursive" { + const tests = [_]struct { + arr: []const i32, + target: i32, + exp: bool, + }{ + .{ + .arr = &[_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + .target = 7, + .exp = true, + }, + .{ + .arr = &[_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + .target = 42, + .exp = false, + }, + .{ + .arr = &[_]i32{42}, + .target = 42, + .exp = true, + }, + .{ + .arr = &[_]i32{1}, + .target = 42, + .exp = false, + }, + .{ + .arr = &[_]i32{}, + .target = 42, + .exp = false, + }, + }; + + for (tests) |t| { + try expect(binarySearch(@TypeOf(t.target), t.arr, t.target) == t.exp); + } +} diff --git a/03_recursion/zig/06_find_max.zig b/03_recursion/zig/06_find_max.zig new file mode 100644 index 00000000..58170ae9 --- /dev/null +++ b/03_recursion/zig/06_find_max.zig @@ -0,0 +1,47 @@ +const print = @import("std").debug.print; +const expect = @import("std").testing.expect; + +pub fn main() void { + print("{}\n", .{findMax(i32, &[_]i32{ 1, 2, 3, 4 })}); +} + +fn findMax(comptime T: type, arr: []const T) T { + switch (arr.len) { + 0 => return 0, + 1 => return arr[0], + else => { + const x = findMax(T, arr[1..]); + if (arr[0] > x) { + return arr[0]; + } else return x; + }, + } +} + +test "find max" { + const tests = [_]struct { + arr: []const i32, + exp: i32, + }{ + .{ + .arr = &[_]i32{ 1, 2, 3, 4 }, + .exp = 4, + }, + .{ + .arr = &[_]i32{ 8, 42, 3, 1 }, + .exp = 42, + }, + .{ + .arr = &[_]i32{42}, + .exp = 42, + }, + .{ + .arr = &[_]i32{}, + .exp = 0, + }, + }; + + for (tests) |t| { + try expect(findMax(@TypeOf(t.exp), t.arr) == t.exp); + } +} diff --git a/03_recursion/zig/07_sum_array.zig b/03_recursion/zig/07_sum_array.zig new file mode 100644 index 00000000..104c22dd --- /dev/null +++ b/03_recursion/zig/07_sum_array.zig @@ -0,0 +1,38 @@ +const print = @import("std").debug.print; +const expect = @import("std").testing.expect; + +pub fn main() void { + print("{}\n", .{sumArray(i32, &[_]i32{ 1, 2, 3, 4 })}); +} + +fn sumArray(comptime T: type, arr: []const T) T { + switch (arr.len) { + 0 => return 0, + 1 => return arr[0], + else => return arr[0] + sumArray(T, arr[1..]), + } +} + +test "sum array" { + const tests = [_]struct { + arr: []const i32, + exp: i32, + }{ + .{ + .arr = &[_]i32{ 1, 2, 3, 4 }, + .exp = 10, + }, + .{ + .arr = &[_]i32{42}, + .exp = 42, + }, + .{ + .arr = &[_]i32{}, + .exp = 0, + }, + }; + + for (tests) |t| { + try expect(sumArray(@TypeOf(t.exp), t.arr) == t.exp); + } +} diff --git a/04_quicksort/ES6/01_loop_sum.js b/04_quicksort/ES6/01_loop_sum.js index e02fa914..102c1dea 100644 --- a/04_quicksort/ES6/01_loop_sum.js +++ b/04_quicksort/ES6/01_loop_sum.js @@ -1,12 +1,12 @@ /** - * Sums values in array by loop "for" - * @param {Array} arr Array of numbers - * @return {number} Sum of the numbers + * Sums values in the array by loop "for" + * @param {Array} array Array of numbers + * @returns {number} Sum of the numbers */ -const sumLoop = arr => { +const sumLoop = array => { let result = 0; - for (let i = 0; i < arr.length; i++) { - result += arr[i]; + for (let i = 0; i < array.length; i++) { + result += array[i]; } return result; }; diff --git a/04_quicksort/ES6/01_loop_sum_reduce_version.js b/04_quicksort/ES6/01_loop_sum_reduce_version.js index 22de0b36..ca41359c 100644 --- a/04_quicksort/ES6/01_loop_sum_reduce_version.js +++ b/04_quicksort/ES6/01_loop_sum_reduce_version.js @@ -1,8 +1,8 @@ /** - * Sums values in array by function "reduce" - * @param {Array} arr Array of numbers - * @return {number} Sum of the numbers + * Sums values in the array by function "reduce" + * @param {Array} array Array of numbers + * @returns {number} Sum of the numbers */ -const sumReduce = arr => arr.reduce((curr, prev) => curr + prev); +const sumReduce = array => array.reduce((prev, curr) => prev + curr); console.log(sumReduce([1, 2, 3, 4])); // 10 diff --git a/04_quicksort/ES6/02_recursive_sum.js b/04_quicksort/ES6/02_recursive_sum.js index f8e55d55..abe904b0 100644 --- a/04_quicksort/ES6/02_recursive_sum.js +++ b/04_quicksort/ES6/02_recursive_sum.js @@ -1,8 +1,8 @@ -const sum = (list) => { - if (list.length === 0) { - return 0; - } - return list[0] + sum(list.slice(1)); -}; +/** + * Sums values in the array by recursive + * @param {Array} array Array of numbers + * @returns {number} Sum of the numbers + */ +const sum = array => (array.length === 0 ? 0 : array[0] + sum(array.slice(1))); console.log(sum([1, 2, 3, 4])); // 10 diff --git a/04_quicksort/ES6/03_recursive_count.js b/04_quicksort/ES6/03_recursive_count.js index 417340d5..19ce7235 100644 --- a/04_quicksort/ES6/03_recursive_count.js +++ b/04_quicksort/ES6/03_recursive_count.js @@ -1,8 +1,8 @@ -const count = (list) => { - if (list.length === 0) { - return 0; - } - return 1 + count(list.slice(1)); -}; +/** + * Count the number of elements in the array + * @param {Array} array Array of numbers + * @returns {number} The number of elements in the array + */ +const count = array => (array.length === 0 ? 0 : 1 + count(array.slice(1))); console.log(count([0, 1, 2, 3, 4, 5])); // 6 diff --git a/04_quicksort/ES6/04_loop_count.js b/04_quicksort/ES6/04_loop_count.js new file mode 100644 index 00000000..676f8cc6 --- /dev/null +++ b/04_quicksort/ES6/04_loop_count.js @@ -0,0 +1,21 @@ +/** + * Count the number of elements in the array + * @param {Array} array Array of numbers + * @returns {number} The number of elements in the array + */ + const countLoop = (array) => { + let result = 0; + + if (array.length === 0) { + return result; + } + + for (let i = 0; i < array.length; i += 1) { + result += 1; + } + + return result; + } + + console.log(countLoop([3,5,8,11])) //4 + console.log(countLoop([])) // 0 \ No newline at end of file diff --git a/04_quicksort/ES6/04_recursive-max.js b/04_quicksort/ES6/04_recursive-max.js deleted file mode 100644 index 5e237b2a..00000000 --- a/04_quicksort/ES6/04_recursive-max.js +++ /dev/null @@ -1,9 +0,0 @@ -const max = (list) => { - if (list.length === 2) { - return list[0] > list[1] ? list[0] : list[1]; - } - const subMax = max(list.slice(1)); - return list[0] > subMax ? list[0] : subMax; -}; - -console.log(max([1, 5, 10, 25, 16, 1])); // 25 diff --git a/04_quicksort/ES6/05_loop_count_reduce_version.js b/04_quicksort/ES6/05_loop_count_reduce_version.js new file mode 100644 index 00000000..e96cec35 --- /dev/null +++ b/04_quicksort/ES6/05_loop_count_reduce_version.js @@ -0,0 +1,9 @@ + /** + * Count the number of elements in the array + * @param {Array} array Array of numbers + * @returns {number} The number of elements in the array + */ + const countReduce = (array) => array.reduce((count, next) => count += 1, 0); + + console.log(countReduce([5,8,11,13])) // 4 + console.log(countReduce([]))// 0 \ No newline at end of file diff --git a/04_quicksort/ES6/05_quicksort.js b/04_quicksort/ES6/05_quicksort.js deleted file mode 100644 index 7014216a..00000000 --- a/04_quicksort/ES6/05_quicksort.js +++ /dev/null @@ -1,11 +0,0 @@ -const quickSort = (array) => { - if (array.length < 2) { - return array; - } - const pivot = array[0]; - const keysAreLessPivot = array.slice(1).filter(key => key <= pivot); - const keysAreMorePivot = array.slice(1).filter(key => key > pivot); - return [...quickSort(keysAreLessPivot), pivot, ...quickSort(keysAreMorePivot)]; -}; - -console.log(quickSort([10, 5, 2, 3])); // [2, 3, 5, 10] diff --git a/04_quicksort/ES6/06_euclidean_algorithm_set_numbers.js b/04_quicksort/ES6/06_euclidean_algorithm_set_numbers.js deleted file mode 100644 index cd3f16d7..00000000 --- a/04_quicksort/ES6/06_euclidean_algorithm_set_numbers.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Recursive function of Euclidean algorithm for two numbers - * - * @param {number} a first number - * @param {number} b second number (base case) - * - * @return {number} GCD (greatest common divisor) - */ -let gcdOfTwo = ( a, b ) => { - if ( !b ) { - return a; - } - return gcdOfTwo( b, a % b ); -}; - -/** - * Recursive function of Euclidean algorithm for set of the numbers - * - * @param {Array} set Set of the numbers - * - * @return {number} GCD (greatest common divisor) - */ -let gcdOfSet = ( set ) => { - let result = set[0]; - let newArr = Array.prototype.slice.call( set, 1 ); - - newArr.map( ( el ) => { - result = gcdOfTwo( result, el ); - } ); - - return result; -}; - -const set = [1680, 640, 3360, 160, 240, 168000]; - -console.log( gcdOfSet( set ) ); // 80 diff --git a/04_quicksort/ES6/06_recursive-max.js b/04_quicksort/ES6/06_recursive-max.js new file mode 100644 index 00000000..6580e2ee --- /dev/null +++ b/04_quicksort/ES6/06_recursive-max.js @@ -0,0 +1,16 @@ +/** + * Calculate the largest number + * This solution only works for arrays longer than one + * @param {Array} array Array of numbers + * @returns {number} The largest number + */ +const max = (array) => { + if (array.length === 0) return 0; + if (array.length === 1) { + return array[0]; + } + const subMax = max(array.slice(1)); + return array[0] > subMax ? array[0] : subMax; +}; + +console.log(max([1, 5, 10, 25, 16, 1])); // 25 diff --git a/04_quicksort/ES6/07_euclidean_algorithm_two_numbers.js b/04_quicksort/ES6/07_euclidean_algorithm_two_numbers.js deleted file mode 100644 index 07483698..00000000 --- a/04_quicksort/ES6/07_euclidean_algorithm_two_numbers.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Recursive function of Euclidean algorithm - * - * @param {number} a first number - * @param {number} b second number (base case) - * - * @return {number} GCD (greatest common divisor) - */ -let getGCD = ( a, b ) => { - if ( !b ) { - return a; - } - return getGCD( b, a % b ); -}; - -const a = 1680; -const b = 640; - -console.log( getGCD( a, b ) ); // 80 diff --git a/04_quicksort/ES6/07_loop_max.js b/04_quicksort/ES6/07_loop_max.js new file mode 100644 index 00000000..06f49da9 --- /dev/null +++ b/04_quicksort/ES6/07_loop_max.js @@ -0,0 +1,23 @@ +/** + * Calculate the largest number + * This solution works for arrays of any length + * @param {Array} array Array of numbers + * @returns {number} The argest number + */ + const maxLoop = (array) => { + let result = 0; + + if (array.length === 0) { + return result; + } + + for (let i = 0; i < array.length; i += 1) { + if (array[i] > result) { + result = array[i] + } + } + return result; + }; + + console.log(maxLoop([2,5,7,22,11])); // 22 + console.log(maxLoop([])) // 0 \ No newline at end of file diff --git a/04_quicksort/ES6/08_loop_max_reduce_version.js b/04_quicksort/ES6/08_loop_max_reduce_version.js new file mode 100644 index 00000000..ea9fb225 --- /dev/null +++ b/04_quicksort/ES6/08_loop_max_reduce_version.js @@ -0,0 +1,10 @@ +/** + * Calculate the largest number + * This solution works for arrays of any length + * @param {Array} array Array of numbers + * @returns {number} The argest number + */ + const maxReduce = (array) => array.reduce((curr, next) => next > curr ? next : curr, 0); + + console.log(maxReduce([1,3,11,7])) // 11 + console.log(maxReduce([])) // 0 \ No newline at end of file diff --git a/04_quicksort/ES6/09_quicksort.js b/04_quicksort/ES6/09_quicksort.js new file mode 100644 index 00000000..c3c7d479 --- /dev/null +++ b/04_quicksort/ES6/09_quicksort.js @@ -0,0 +1,18 @@ +/** + * Quick array sorting + * @param {Array} array Source array + * @returns {Array} Sorted array + */ +const quickSort = array => { + if (array.length < 2) return array; + const pivot = array[0]; + const keysAreLessPivot = array.slice(1).filter(key => key <= pivot); + const keysAreMorePivot = array.slice(1).filter(key => key > pivot); + return [ + ...quickSort(keysAreLessPivot), + pivot, + ...quickSort(keysAreMorePivot) + ]; +}; + +console.log(quickSort([10, 5, 2, 3])); // [2, 3, 5, 10] diff --git a/04_quicksort/ES6/10_euclidean_algorithm_two_numbers.js b/04_quicksort/ES6/10_euclidean_algorithm_two_numbers.js new file mode 100644 index 00000000..27873354 --- /dev/null +++ b/04_quicksort/ES6/10_euclidean_algorithm_two_numbers.js @@ -0,0 +1,9 @@ +/** + * Recursive function of Euclidean algorithm + * @param {number} a first number + * @param {number} b second number (base case) + * @returns {number} GCD (greatest common divisor) + */ +const getGCD = (a, b) => (!b ? a : getGCD(b, a % b)); + +console.log(getGCD(1680, 640)); // 80 diff --git a/04_quicksort/ES6/11_euclidean_algorithm_set_numbers.js b/04_quicksort/ES6/11_euclidean_algorithm_set_numbers.js new file mode 100644 index 00000000..9e106b4e --- /dev/null +++ b/04_quicksort/ES6/11_euclidean_algorithm_set_numbers.js @@ -0,0 +1,27 @@ +/** + * Recursive function of Euclidean algorithm for two numbers + * @param {number} a first number + * @param {number} b second number (base case) + * @returns {number} GCD (greatest common divisor) + */ +const gcdOfTwo = (a, b) => (!b ? a : gcdOfTwo(b, a % b)); + +/** + * Recursive function of Euclidean algorithm for set of the numbers + * @param {Array} set Set of the numbers + * @returns {number} GCD (greatest common divisor) + */ +const gcdOfSet = set => { + let result = set[0]; + let newArr = set.slice(1); + + newArr.map(el => { + result = gcdOfTwo(result, el); + }); + + return result; +}; + +const set = [1680, 640, 3360, 160, 240, 168000]; + +console.log(gcdOfSet(set)); // 80 diff --git a/04_quicksort/c++11/02_recursive_sum.cpp b/04_quicksort/c++11/02_recursive_sum.cpp index b75a8201..652fe0cb 100644 --- a/04_quicksort/c++11/02_recursive_sum.cpp +++ b/04_quicksort/c++11/02_recursive_sum.cpp @@ -10,7 +10,7 @@ T sum(std::vector arr) { T last_num = arr.back(); // save last number value arr.pop_back(); // and remove it from array for next recursive call - return first_num + sum(arr); + return last_num + sum(arr); } int main() { diff --git a/04_quicksort/c/04_recursive_max.c b/04_quicksort/c/04_recursive_max.c new file mode 100644 index 00000000..f64cc4ca --- /dev/null +++ b/04_quicksort/c/04_recursive_max.c @@ -0,0 +1,19 @@ +#include + +int max(int *arr, int index, int size){ + //base case + if (index == size - 1) + return arr[index]; + + int sub_max = max(arr, index + 1, size); + + return (arr[index] > sub_max) ? arr[index] : sub_max; +} + +int main(void){ + int arr[] = {2,3,6,5,5}; + // the C way of calculating the size of an array + int size = sizeof(arr) / sizeof(arr[0]); + printf("%d", max(arr, 0, size)); + return 0; +} diff --git a/04_quicksort/csharp/06_GetGCD/program.cs b/04_quicksort/csharp/06_GetGCD/program.cs new file mode 100644 index 00000000..51bc3851 --- /dev/null +++ b/04_quicksort/csharp/06_GetGCD/program.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace GCD +{ + public class Program + { + static void Main(string[] args) + { + var lst = new List { 32, 696, 40, 50 }; + var GCD = GetGCD(640, 1680); + var GCDList = GetGCDList(lst); + + Console.WriteLine(GCD); + Console.WriteLine(GCDList); + } + + //Get great Comman Divisor + public static int GetGCD(int firstNumber, int secondNumber) + => secondNumber == default ? firstNumber : GetGCD(secondNumber, firstNumber % secondNumber); + + //Get great Comman Divisor of list + public static int GetGCDList(IEnumerable lst) + { + var result = lst.FirstOrDefault(); + + if (lst.Count() > 2) + { + result = GetGCD(result, GetGCDList(lst.Skip(1))); + } + else + { + result = GetGCD(result, lst.Skip((1)).FirstOrDefault()); + } + + return result; + } + } +} \ No newline at end of file diff --git a/04_quicksort/d/01_loop_sum.d b/04_quicksort/d/01_loop_sum.d new file mode 100644 index 00000000..df5bc29a --- /dev/null +++ b/04_quicksort/d/01_loop_sum.d @@ -0,0 +1,14 @@ +module app; + +import std; + +T loop_sum(T[] arr) { + T total; + foreach(x; arr) + total += x; + return total; +} + +void main() { + writeln(loop_sum([1,2,3,4])); +} diff --git a/04_quicksort/d/02_recursive_sum.d b/04_quicksort/d/02_recursive_sum.d new file mode 100644 index 00000000..891b6861 --- /dev/null +++ b/04_quicksort/d/02_recursive_sum.d @@ -0,0 +1,13 @@ +module app; + +import std; + +T rec_sum(T[] list) { + if (list.empty) + return 0; + return list[0] + sum(list[1..$]); +} + +void main() { + writeln(rec_sum([1,2,3,4])); +} diff --git a/04_quicksort/d/03_recursive_count.d b/04_quicksort/d/03_recursive_count.d new file mode 100644 index 00000000..b197479c --- /dev/null +++ b/04_quicksort/d/03_recursive_count.d @@ -0,0 +1,13 @@ +module app; + +import std; + +T rec_count(T[] list) { + if (list.empty) + return 0; + return 1 + rec_count(list[1..$]); +} + +void main() { + writeln(rec_count([1,2,3,4])); +} diff --git a/04_quicksort/d/04_recursive_max.d b/04_quicksort/d/04_recursive_max.d new file mode 100644 index 00000000..2f176d12 --- /dev/null +++ b/04_quicksort/d/04_recursive_max.d @@ -0,0 +1,19 @@ +module app; + +import std; + +T rec_max(T)(T[] list) { + if (list.empty) + return T.init; + if (list.length == 1) + return list[0]; + else { + auto max_num = rec_max(list[1..$]); + return list[0] > max_num ? list[0] : max_num; + } +} + +void main() { + writeln(rec_max([1,2,3])); +} + diff --git a/04_quicksort/d/05_quicksort.d b/04_quicksort/d/05_quicksort.d new file mode 100644 index 00000000..7b943a78 --- /dev/null +++ b/04_quicksort/d/05_quicksort.d @@ -0,0 +1,18 @@ +module app; + +import std; + +T[] quicksort(T[] arr) { + if (arr.length < 2) + return arr; + else { + auto pivot = arr[0]; + auto less = arr.filter!(el => el < pivot).array; + auto greater = arr.filter!(el => el > pivot).array; + return quicksort(less) ~ arr.filter!(el => el == pivot).array ~ quicksort(greater); + } +} + +void main() { + writeln(quicksort([10, 5, 2, 3])); +} diff --git a/04_quicksort/dart/04_quicksort/quicksort.dart b/04_quicksort/dart/04_quicksort/quicksort.dart new file mode 100644 index 00000000..a7803072 --- /dev/null +++ b/04_quicksort/dart/04_quicksort/quicksort.dart @@ -0,0 +1,21 @@ +void main(List args) { + final Stopwatch stopwatch = Stopwatch()..start(); + print(quickSort([0, 21, 3, 1, 6, 5, 0, 81, 2, 14, 56, 32, 1, 9, 8])); + stopwatch.stop(); + print(stopwatch.elapsedMilliseconds); +} + +List quickSort(List toOrder) { + if (toOrder.length < 2) { + return toOrder; + } + final int mid = toOrder.length ~/ 2; + + final int pivot = toOrder[mid]; + toOrder.removeAt(mid); + final List lowers = + List.from(toOrder.where((element) => element <= pivot)); + final List highers = + List.from(toOrder.where((element) => element > pivot)); + return quickSort(lowers) + [pivot] + quickSort(highers); +} diff --git a/04_quicksort/f#/QuickSort/Program.fs b/04_quicksort/f#/QuickSort/Program.fs new file mode 100644 index 00000000..e4b8884b --- /dev/null +++ b/04_quicksort/f#/QuickSort/Program.fs @@ -0,0 +1,21 @@ +// Learn more about F# at http://fsharp.org + +open System + +[] +let main argv = + let numbers = [|3; 9; 10; 1; 4; 2; 6; 5; 8; 7|] + + let rec quickSort(arr: int[]) = + if arr.Length < 2 + then arr + else + let pivot = arr.[0] + let arrExcpetPivot = arr |> Seq.skip(1) |> Seq.toArray + let lessElements = quickSort arrExcpetPivot |> Seq.filter(fun n -> n <= pivot) |> Seq.toArray + let greaterElements = quickSort arrExcpetPivot |> Seq.filter(fun n -> n > pivot) |> Seq.toArray + + Seq.append (Seq.append lessElements [|pivot|]) greaterElements |> Seq.toArray + + let sorted = quickSort(numbers) + 0 diff --git a/04_quicksort/golang/04_recursive_max.go b/04_quicksort/golang/04_recursive_max.go index dd98eca6..9ada753c 100644 --- a/04_quicksort/golang/04_recursive_max.go +++ b/04_quicksort/golang/04_recursive_max.go @@ -2,21 +2,18 @@ package main import "fmt" -func max(list []int) int { - if len(list) == 2 { - if list[0] > list[1] { - return list[0] - } - return list[1] - } +func main() { + fmt.Println(max([]int{1, 5, 10, 25, 16, 1})) +} + +func max(arr []int) int { - subMax := max(list[1:]) - if list[0] > subMax { - return list[0] + if len(arr) == 1 { + return arr[0] } - return subMax -} -func main() { - fmt.Println(max([]int{1, 5, 10, 25, 16, 1})) + if arr[0] > max(arr[1:]) { + return arr[0] + } + return max(arr[1:]) } diff --git a/04_quicksort/javascript/01_loop_sum.js b/04_quicksort/javascript/01_loop_sum.js index 2037a78d..755ace30 100644 --- a/04_quicksort/javascript/01_loop_sum.js +++ b/04_quicksort/javascript/01_loop_sum.js @@ -1,15 +1,16 @@ +"use strict"; + /** - * Sums values in array by loop "for" - * @param {Array} arr Array of numbers - * @return {total} Sum of the numbers + * Sums values in the array by loop "for" + * @param {Array} array Array of numbers + * @returns {total} Sum of the numbers */ - -function sum(arr) { - let total = 0; - for (let i = 0; i < arr.length; i++) { - total += arr[i]; - } - return total; +function sum(array) { + let total = 0; + for (let i = 0; i < array.length; i++) { + total += array[i]; + } + return total; } console.log(sum([1, 2, 3, 4])); // 10 diff --git a/04_quicksort/javascript/01_loop_sum_reduce_version.js b/04_quicksort/javascript/01_loop_sum_reduce_version.js index 101871da..e36ebfd8 100644 --- a/04_quicksort/javascript/01_loop_sum_reduce_version.js +++ b/04_quicksort/javascript/01_loop_sum_reduce_version.js @@ -1,12 +1,10 @@ +"use strict"; + /** - * Sums values in array by function "reduce" - * @param {Array} arr Array of numbers - * @return {number} Sum of the numbers + * Sums values in the array by function "reduce" + * @param {Array} array Array of numbers + * @returns {number} Sum of the numbers */ -function sumReduce(arr) { - return arr.reduce(function(curr, prev) { - return curr + prev; - }); -} +const sumReduce = (array) => array.reduce((prev, cur) => prev + cur, 0); console.log(sumReduce([1, 2, 3, 4])); // 10 diff --git a/04_quicksort/javascript/02_recursive_sum.js b/04_quicksort/javascript/02_recursive_sum.js index 06c9dc33..ab745631 100644 --- a/04_quicksort/javascript/02_recursive_sum.js +++ b/04_quicksort/javascript/02_recursive_sum.js @@ -1,13 +1,14 @@ +'use strict'; + /** - * Sums values in array recursively - * @param {Array} arr Array of numbers - * @return {number} Sum of the numbers + * Sums values in the array by recursive + * @param {Array} array Array of numbers + * @returns {number} Sum of the numbers */ -function sumRecursive(arr) { - if (arr.length == 1) { - return arr[0]; - } +const sumRecursive = (arr = []) => { + if (!arr.length) return 0; return arr[0] + sumRecursive(arr.slice(1)); -} +}; + console.log(sumRecursive([1, 2, 3, 4])); // 10 diff --git a/04_quicksort/javascript/03_recursive_count.js b/04_quicksort/javascript/03_recursive_count.js index 139acfcd..882650cf 100644 --- a/04_quicksort/javascript/03_recursive_count.js +++ b/04_quicksort/javascript/03_recursive_count.js @@ -1,10 +1,13 @@ -'use strict'; +"use strict"; -function count(list) { - if (list.length === 0) { - return 0; - } - return 1 + count(list.slice(1)); +/** + * Count the number of elements in the array + * @param {Array} array Array of numbers + * @returns {number} The number of elements in the array + */ +function count(array) { + if (array.length === 0) return 0; + return 1 + count(array.slice(1)); } console.log(count([0, 1, 2, 3, 4, 5])); // 6 diff --git a/04_quicksort/javascript/04_recursive_max.js b/04_quicksort/javascript/04_recursive_max.js index fe457e9c..c51aebfe 100644 --- a/04_quicksort/javascript/04_recursive_max.js +++ b/04_quicksort/javascript/04_recursive_max.js @@ -1,11 +1,32 @@ -'use strict'; - -function max(list) { - if (list.length === 2) { - return list[0] > list[1] ? list[0] : list[1]; - } - let sub_max = max(list.slice(1)); - return list[0] > sub_max ? list[0] : sub_max; +"use strict"; + +/** + * Calculate the largest number + * This solution only works for arrays longer than one + * @param {Array} array Array of numbers + * @returns {number} The argest number + */ +function max(array) { + if (array.length === 2) return array[0] > array[1] ? array[0] : array[1]; + let sub_max = max(array.slice(1)); + return array[0] > sub_max ? array[0] : sub_max; +} + +/** + * Calculate the largest number + * This solution works for arrays of any length and returns the smallest possible number for empty arrays + * @param {Array} array Array of numbers + * @param {number} max Maximum value + * @returns {number} The largest number + */ +function alternativeSolutionMax(array, max = Number.MIN_VALUE) { + return array.length === 0 + ? max + : alternativeSolutionMax(array.slice(1), array[0] > max ? array[0] : max); } console.log(max([1, 5, 10, 25, 16, 1])); // 25 +console.log(alternativeSolutionMax([1, 5, 10, 25, 16, 1])); // 25 + +console.log(max([])); // RangeError: Maximum call stack size exceeded +console.log(alternativeSolutionMax([])); // Number.MIN_VALUE diff --git a/04_quicksort/javascript/05_quicksort.js b/04_quicksort/javascript/05_quicksort.js deleted file mode 100644 index e31a9490..00000000 --- a/04_quicksort/javascript/05_quicksort.js +++ /dev/null @@ -1,19 +0,0 @@ -function quicksort(array) { - if (array.length < 2) { - // base case, arrays with 0 or 1 element are already "sorted" - return array; - } - // recursive case - let pivot = array[0]; - // sub-array of all the elements less than the pivot - let less = array.slice(1).filter(function(el) { - return el <= pivot; - }); - // sub-array of all the elements greater than the pivot - let greater = array.slice(1).filter(function(el) { - return el > pivot; - }); - return quicksort(less).concat([pivot], quicksort(greater)); -} - -console.log(quicksort([10, 5, 2, 3])); // [2, 3, 5, 10] diff --git a/04_quicksort/javascript/quick_sort/05_quicksort.js b/04_quicksort/javascript/quick_sort/05_quicksort.js new file mode 100644 index 00000000..483baf30 --- /dev/null +++ b/04_quicksort/javascript/quick_sort/05_quicksort.js @@ -0,0 +1,24 @@ +"use strict"; + +/** + * Quick array sorting + * @param {Array} array Source array + * @returns {Array} Sorted array + */ +function quicksort(array) { + // base case, arrays with 0 or 1 element are already "sorted" + if (array.length < 2) return array; + // recursive case + let pivot = array[0]; + // sub-array of all the elements less than the pivot + let less = array.slice(1).filter(function (el) { + return el <= pivot; + }); + // sub-array of all the elements greater than the pivot + let greater = array.slice(1).filter(function (el) { + return el > pivot; + }); + return quicksort(less).concat(pivot, quicksort(greater)); +} + +console.log(quicksort([10, 5, 2, 3])); diff --git a/04_quicksort/javascript/quick_sort/Test_report.binary_quick_sort.docx b/04_quicksort/javascript/quick_sort/Test_report.binary_quick_sort.docx new file mode 100644 index 00000000..042c1977 Binary files /dev/null and b/04_quicksort/javascript/quick_sort/Test_report.binary_quick_sort.docx differ diff --git a/04_quicksort/julia/01_loop_sum.jl b/04_quicksort/julia/01_loop_sum.jl new file mode 100644 index 00000000..e15e502a --- /dev/null +++ b/04_quicksort/julia/01_loop_sum.jl @@ -0,0 +1,11 @@ +using Test + +function sum(arr) + total = 0 + for x in arr + total += x + end + return total +end + +@test sum([1,2,3,4]) == 10 diff --git a/04_quicksort/julia/02_recursive_sum.jl b/04_quicksort/julia/02_recursive_sum.jl new file mode 100644 index 00000000..7933a3a8 --- /dev/null +++ b/04_quicksort/julia/02_recursive_sum.jl @@ -0,0 +1,10 @@ +using Test + +function sum(arr) + if isempty(arr) + return 0 + end + return arr[1] + sum(arr[2:end]) +end + +@test sum([1,2,3,4]) == 10 diff --git a/04_quicksort/julia/03_recursive_cout.jl b/04_quicksort/julia/03_recursive_cout.jl new file mode 100644 index 00000000..3e73ebf4 --- /dev/null +++ b/04_quicksort/julia/03_recursive_cout.jl @@ -0,0 +1,10 @@ +using Test + +function count(arr) + if isempty(arr) + return 0 + end + return 1 + count(arr[2:end]) +end + +@test count([1,2,3,4]) == 4 diff --git a/04_quicksort/julia/04_recursive_max.jl b/04_quicksort/julia/04_recursive_max.jl new file mode 100644 index 00000000..1eee2a43 --- /dev/null +++ b/04_quicksort/julia/04_recursive_max.jl @@ -0,0 +1,11 @@ +using Test + +function max_(arr) + if length(arr) == 1 + return arr[1] + end + sub_max = max_(arr[2:end]) + return arr[1] > sub_max ? arr[1] : sub_max +end + +@test max_([1,5,8,20,9,10]) == 20 diff --git a/04_quicksort/julia/05_quick_sort.jl b/04_quicksort/julia/05_quick_sort.jl new file mode 100644 index 00000000..34b2ef24 --- /dev/null +++ b/04_quicksort/julia/05_quick_sort.jl @@ -0,0 +1,11 @@ +using Test + +function quick_sort(arr) + if length(arr) < 2 return arr end + pivot = arr[1] + less = [i for i in arr[2:end] if i <= pivot] + greater = [i for i in arr[2:end] if i > pivot] + return vcat(quick_sort(less), [pivot], quick_sort(greater)) +end + +@test quick_sort([3,5,2,1,4]) == [1,2,3,4,5] diff --git a/04_quicksort/kotlin/04_recursive_max.kt b/04_quicksort/kotlin/04_recursive_max.kt index ab887521..f7b39330 100644 --- a/04_quicksort/kotlin/04_recursive_max.kt +++ b/04_quicksort/kotlin/04_recursive_max.kt @@ -1,5 +1,5 @@ -private fun max(list: IntArray): Int = when { - list.size == 2 -> if (list[0] > list[1]) list[0] else list[1] +private fun max(list: IntArray): Int = when (list.size) { + 2 -> if (list[0] > list[1]) list[0] else list[1] else -> { val subMax = max(list.copyOfRange(1, list.size)) if (list[0] > subMax) list[0] else subMax diff --git a/04_quicksort/kotlin/05_quicksort.kt b/04_quicksort/kotlin/05_quicksort.kt index 3a0c76b9..67507129 100644 --- a/04_quicksort/kotlin/05_quicksort.kt +++ b/04_quicksort/kotlin/05_quicksort.kt @@ -3,10 +3,9 @@ fun quickSort(list: List): List { if (list.size <= 1) return list // recursive case val pivot = list[list.size / 2] - val equal = list.filter { it == pivot } val less = list.filter { it < pivot } val greater = list.filter { it > pivot } - return quickSort(less) + equal + quickSort(greater) + return quickSort(less) + pivot + quickSort(greater) } fun main(args: Array) = println(quickSort(listOf(10, 5, 2, 3))) // [2, 3, 5, 10] diff --git a/04_quicksort/php/05_quicksort.php b/04_quicksort/php/05_quicksort.php index 8bf43173..186505e3 100644 --- a/04_quicksort/php/05_quicksort.php +++ b/04_quicksort/php/05_quicksort.php @@ -6,7 +6,7 @@ function quicksort(array $array) { return $array; } else { // recursive case - $pivot = $array[0]; + $pivot = $array[array_key_first($array)]; var_dump($array); // sub-array of all the elements less than the pivot diff --git a/04_quicksort/python/04_recursive_max.py b/04_quicksort/python/04_recursive_max.py index 908c31ac..717e4f95 100644 --- a/04_quicksort/python/04_recursive_max.py +++ b/04_quicksort/python/04_recursive_max.py @@ -1,8 +1,8 @@ -def max_(lst): - if len(lst) == 0: - return None - if len(lst) == 1: - return lst[0] - else: - sub_max = max_(lst[1:]) - return lst[0] if lst[0] > sub_max else sub_max +def max(lst): + if len(lst) == 0: + return None + if len(lst) == 1: + return lst[0] + else: + max_num = max(lst[1:]) + return lst[0] if lst[0] > max_num else max_num diff --git a/04_quicksort/ruby/04_recursive_max.rb b/04_quicksort/ruby/04_recursive_max.rb index 59e7d948..4770b6b3 100644 --- a/04_quicksort/ruby/04_recursive_max.rb +++ b/04_quicksort/ruby/04_recursive_max.rb @@ -1,9 +1,12 @@ def max(list) - if list.length == 2 - # condition ? then : else - list[0] > list[1] ? list[0] : list[1] + return nil if list.empty? + + if list.length == 1 + list[0] # base case else sub_max = max(list[1..-1]) list[0] > sub_max ? list[0] : sub_max end end + +puts max([2,3,8,5,5]) diff --git a/04_quicksort/rust/Cargo.lock b/04_quicksort/rust/Cargo.lock new file mode 100644 index 00000000..fee3150d --- /dev/null +++ b/04_quicksort/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "quicksort" +version = "0.1.0" diff --git a/04_quicksort/rust/Cargo.toml b/04_quicksort/rust/Cargo.toml new file mode 100644 index 00000000..c33b5101 --- /dev/null +++ b/04_quicksort/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "quicksort" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/04_quicksort/rust/src/main.rs b/04_quicksort/rust/src/main.rs new file mode 100644 index 00000000..18843232 --- /dev/null +++ b/04_quicksort/rust/src/main.rs @@ -0,0 +1,98 @@ +fn rec_sum(list: &[usize]) -> usize { + match list.get(0) { + Some(x) => x + rec_sum(&list[1..]), + None => 0, + } +} + +fn rec_count(list: &[T]) -> usize { + match list.get(0) { + Some(_) => 1 + rec_count(&list[1..]), + None => 0, + } +} + +fn maximum(list: &[T]) -> Option<&T> { + match list.get(0) { + Some(x) => match maximum(&list[1..]) { + Some(max) => { + if x > max { + Some(x) + } else { + Some(max) + } + } + None => Some(x), + }, + None => None, + } +} + +fn quicksort(list: &Vec) -> Vec { + if list.len() < 2 { + list.to_vec() + } else { + let pivot = &list[0]; + + let mut less = vec![]; + let mut greater = vec![]; + + for x in &list[1..] { + if x <= pivot { + less.push(x.clone()); + } else { + greater.push(x.clone()); + } + } + + let mut new = Vec::with_capacity(list.len()); + new.append(&mut quicksort(&less)); + new.push(pivot.clone()); + new.append(&mut quicksort(&greater)); + new + } +} + +fn main() { + let list = vec![10, 5, 2, 12, 3]; + + println!("quicksort: {:?}", quicksort(&list)); + println!("sum: {}", rec_sum(&list)); + println!("count: {}", rec_count(&list)); + println!("maximum: {:?}", maximum(&list)); +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn simple_rec_sum() { + let list = [2, 4, 6]; + let expected = 12; + + let result = rec_sum(&list); + + assert_eq!(result, expected); + } + + #[test] + fn simple_rec_count() { + let list = [2, 4, 6]; + let expected = 3; + + let result = rec_count(&list); + + assert_eq!(result, expected); + } + + #[test] + fn simple_maximum() { + let list = [2, 4, 6, 3]; + let expected = 6; + + let result = maximum(&list); + + assert_eq!(result, Some(&expected)); + } +} diff --git a/04_quicksort/swift/05_quicksort.swift b/04_quicksort/swift/05_quicksort.swift index e017b4d8..9449921e 100644 --- a/04_quicksort/swift/05_quicksort.swift +++ b/04_quicksort/swift/05_quicksort.swift @@ -2,20 +2,17 @@ import Foundation //The following implementation of quick sort is little more classic than described in the book, but we have two use this one because of some “slice” feature limitation with array on Swift 3. Main concept is the same func quicksort (_ array : [T]) -> [T] { - if (array.count < 2) { - // base case, arrays with 0 or 1 element are already "sorted" - return array - } else { - // recursive case - let pivot = array[0] - // sub-array of all the elements less than the pivot - let less = array.filter { $0 < pivot } - // sub-array of all the elements equal to the pivot - let equal = array.filter { $0 == pivot } - // sub-array of all the elements greater than the pivot - let greater = array.filter { $0 > pivot } - return quicksort(less) + equal + quicksort(greater) - } + // base case, arrays with 0 or 1 element are already "sorted" + guard array.count > 1 else { return array } + // recursive case + let pivot = array[0] + // sub-array of all the elements less than the pivot + let less = array.filter { $0 < pivot } + // sub-array of all the elements equal to the pivot + let equal = array.filter { $0 == pivot } + // sub-array of all the elements greater than the pivot + let greater = array.filter { $0 > pivot } + return quicksort(less) + equal + quicksort(greater) } print(quicksort([1, 5, 10, 25, 16, 1])) // => [1, 1, 5, 10, 16, 25] diff --git a/04_quicksort/zig/01_loop_sum.zig b/04_quicksort/zig/01_loop_sum.zig new file mode 100644 index 00000000..a9b94e6a --- /dev/null +++ b/04_quicksort/zig/01_loop_sum.zig @@ -0,0 +1,38 @@ +const print = @import("std").debug.print; +const expect = @import("std").testing.expect; + +pub fn main() void { + var arr = [_]i32{ 1, 2, 3, 4 }; + print("{}\n", .{sum(i32, &arr)}); +} + +fn sum(comptime T: type, arr: []T) T { + var total: T = 0; + for (arr) |x| { + total += x; + } + return total; +} + +test "sum" { + var arr0 = [_]i32{ 1, 2, 3, 4 }; + var arr1 = [_]i32{}; + const tests = [_]struct { + arr: []i32, + exp: i32, + }{ + .{ + .arr = &arr0, + .exp = 10, + }, + .{ + .arr = &arr1, + .exp = 0, + }, + }; + + for (tests) |t| { + const n = sum(@TypeOf(t.exp), t.arr); + try expect(n == t.exp); + } +} diff --git a/04_quicksort/zig/02_recursive_sum.zig b/04_quicksort/zig/02_recursive_sum.zig new file mode 100644 index 00000000..781cfe6e --- /dev/null +++ b/04_quicksort/zig/02_recursive_sum.zig @@ -0,0 +1,37 @@ +const print = @import("std").debug.print; +const expect = @import("std").testing.expect; + +pub fn main() void { + var list = [_]i32{ 1, 2, 3, 4 }; + print("{}\n", .{sum(i32, &list)}); +} + +fn sum(comptime T: type, list: []T) T { + if (list.len == 0) { + return 0; + } + return list[0] + sum(T, list[1..]); +} + +test "sum" { + var arr0 = [_]i32{ 1, 2, 3, 4 }; + var arr1 = [_]i32{}; + const tests = [_]struct { + arr: []i32, + exp: i32, + }{ + .{ + .arr = &arr0, + .exp = 10, + }, + .{ + .arr = &arr1, + .exp = 0, + }, + }; + + for (tests) |t| { + const n = sum(@TypeOf(t.exp), t.arr); + try expect(n == t.exp); + } +} diff --git a/04_quicksort/zig/03_recursive_count.zig b/04_quicksort/zig/03_recursive_count.zig new file mode 100644 index 00000000..487bb67e --- /dev/null +++ b/04_quicksort/zig/03_recursive_count.zig @@ -0,0 +1,40 @@ +const print = @import("std").debug.print; +const expect = @import("std").testing.expect; + +pub fn main() void { + var arr = [_]i32{ 4, 3, 2, 1 }; + print("{}\n", .{count(i32, arr[0..])}); +} + +fn count(comptime T: type, arr: []T) T { + if (arr.len == 0) { + return 0; + } else return 1 + count(T, arr[1..]); +} + +test "count" { + var arr0 = [_]i32{}; + var arr1 = [_]i32{42}; + var arr2 = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + const tests = [_]struct { + arr: []i32, + exp: i32, + }{ + .{ + .arr = &arr0, + .exp = 0, + }, + .{ + .arr = &arr1, + .exp = 1, + }, + .{ + .arr = &arr2, + .exp = 9, + }, + }; + + for (tests) |t| { + try expect(count(@TypeOf(t.exp), t.arr) == t.exp); + } +} diff --git a/04_quicksort/zig/04_recursive_max.zig b/04_quicksort/zig/04_recursive_max.zig new file mode 100644 index 00000000..58170ae9 --- /dev/null +++ b/04_quicksort/zig/04_recursive_max.zig @@ -0,0 +1,47 @@ +const print = @import("std").debug.print; +const expect = @import("std").testing.expect; + +pub fn main() void { + print("{}\n", .{findMax(i32, &[_]i32{ 1, 2, 3, 4 })}); +} + +fn findMax(comptime T: type, arr: []const T) T { + switch (arr.len) { + 0 => return 0, + 1 => return arr[0], + else => { + const x = findMax(T, arr[1..]); + if (arr[0] > x) { + return arr[0]; + } else return x; + }, + } +} + +test "find max" { + const tests = [_]struct { + arr: []const i32, + exp: i32, + }{ + .{ + .arr = &[_]i32{ 1, 2, 3, 4 }, + .exp = 4, + }, + .{ + .arr = &[_]i32{ 8, 42, 3, 1 }, + .exp = 42, + }, + .{ + .arr = &[_]i32{42}, + .exp = 42, + }, + .{ + .arr = &[_]i32{}, + .exp = 0, + }, + }; + + for (tests) |t| { + try expect(findMax(@TypeOf(t.exp), t.arr) == t.exp); + } +} diff --git a/04_quicksort/zig/05_quicksort.zig b/04_quicksort/zig/05_quicksort.zig new file mode 100644 index 00000000..6c99bb13 --- /dev/null +++ b/04_quicksort/zig/05_quicksort.zig @@ -0,0 +1,74 @@ +const std = @import("std"); +const print = std.debug.print; +const expect = std.testing.expect; +const heap = std.heap; +const mem = std.mem; + +pub fn main() !void { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + var arena = heap.ArenaAllocator.init(gpa.allocator()); + defer arena.deinit(); + + var s = [_]u8{ 5, 3, 6, 2, 10 }; + + print("{d}\n", .{try quicksort(u8, arena.allocator(), &s)}); +} + +fn quicksort(comptime T: type, allocator: mem.Allocator, s: []const T) anyerror![]const T { + // base case, arrays with 0 or 1 element are already "sorted" + if (s.len < 2) { + return s; + } + + var lower = std.ArrayList(T).init(allocator); + var higher = std.ArrayList(T).init(allocator); + + const pivot = s[0]; + for (s[1..]) |item| { + if (item <= pivot) { + try lower.append(item); + } else { + try higher.append(item); + } + } + + const low = try quicksort(T, allocator, lower.items); + const high = try quicksort(T, allocator, higher.items); + + var res = std.ArrayList(T).init(allocator); + try res.appendSlice(low); + try res.append(pivot); + try res.appendSlice(high); + + return res.items; +} + +test "quicksort" { + var arena = heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + + const tests = [_]struct { + s: []const u8, + exp: []const u8, + }{ + .{ + .s = &[_]u8{}, + .exp = &[_]u8{}, + }, + .{ + .s = &[_]u8{42}, + .exp = &[_]u8{42}, + }, + .{ + .s = &[_]u8{ 3, 2, 1 }, + .exp = &[_]u8{ 1, 2, 3 }, + }, + }; + + for (tests) |t| { + const res = try quicksort(u8, arena.allocator(), t.s); + try expect(res.len == t.exp.len); + for (res, 0..) |e, i| + try expect(e == t.exp[i]); + } +} diff --git a/04_quicksort/zig/06_quicksort_parallel.zig b/04_quicksort/zig/06_quicksort_parallel.zig new file mode 100644 index 00000000..8c88c8a1 --- /dev/null +++ b/04_quicksort/zig/06_quicksort_parallel.zig @@ -0,0 +1,100 @@ +const std = @import("std"); +const print = std.debug.print; +const expect = std.testing.expect; +const heap = std.heap; +const mem = std.mem; + +// pub const io_mode = .evented; + +pub fn main() !void { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + var arena = heap.ArenaAllocator.init(gpa.allocator()); + defer arena.deinit(); + + var u = [_]u8{ 5, 3, 6, 2, 10 }; + + var s = try std.ArrayList(u8).initCapacity(arena.allocator(), u.len); + try quicksort(u8, arena.allocator(), &u, &s); + print("{d}\n", .{s.items}); +} + +fn quicksort(comptime T: type, allocator: mem.Allocator, u: []const T, s: *std.ArrayList(T)) !void { + if (u.len < 2) { + try s.appendSlice(u); + return; + } + + var lower = std.ArrayList(T).init(allocator); + var higher = std.ArrayList(T).init(allocator); + + const pivot = u[0]; + for (u[1..]) |item| { + if (item <= pivot) { + try lower.append(item); + } else { + try higher.append(item); + } + } + + // NOTE: zig has temporary removed the async/await syntax since v0.11.0 + // + // const low_frame = try allocator.create(@Frame(quicksort)); + // low_frame.* = async quicksort(allocator, lower.items); + // const high = try quicksort(allocator, higher.items); + // const low = try await low_frame; + + var low = try std.ArrayList(T).initCapacity(allocator, lower.items.len); + var high = try std.ArrayList(T).initCapacity(allocator, higher.items.len); + + var low_handle = try std.Thread.spawn( + .{}, + quicksort, + .{ T, allocator, lower.items, &low }, + ); + var high_handle = try std.Thread.spawn( + .{}, + quicksort, + .{ T, allocator, higher.items, &high }, + ); + low_handle.join(); + high_handle.join(); + + const lows = try low.toOwnedSlice(); + const highs = try high.toOwnedSlice(); + try s.appendSlice(lows); + try s.append(pivot); + try s.appendSlice(highs); + + return; +} + +test "quicksort" { + var arena = heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + + const tests = [_]struct { + s: []const u8, + exp: []const u8, + }{ + .{ + .s = &[_]u8{}, + .exp = &[_]u8{}, + }, + .{ + .s = &[_]u8{42}, + .exp = &[_]u8{42}, + }, + .{ + .s = &[_]u8{ 3, 2, 1 }, + .exp = &[_]u8{ 1, 2, 3 }, + }, + }; + + for (tests) |t| { + var res = std.ArrayList(u8).init(arena.allocator()); + try quicksort(u8, arena.allocator(), t.s, &res); + try expect(res.items.len == t.exp.len); // length not matching + for (res.items, 0..) |e, i| + try expect(e == t.exp[i]); // element not matching + } +} diff --git a/05_hash_tables/ES6/02_check_voter.js b/05_hash_tables/ES6/02_check_voter.js index d2aeeb1c..1bf5d706 100644 --- a/05_hash_tables/ES6/02_check_voter.js +++ b/05_hash_tables/ES6/02_check_voter.js @@ -1,14 +1,18 @@ const voted = {}; -const checkVoter = (name) => { + +/** + * Vote check + * @param {string} name Voter name + */ +const checkVoter = name => { if (voted[name]) { - console.log('kick them out!'); + console.log("kick them out!"); } else { voted[name] = true; - console.log('let them vote!'); + console.log("let them vote!"); } }; - -checkVoter('tom'); // let them vote! -checkVoter('mike'); // let them vote! -checkVoter('mike'); // kick them out! +checkVoter("tom"); // let them vote! +checkVoter("mike"); // let them vote! +checkVoter("mike"); // kick them out! diff --git a/05_hash_tables/d/01_price_of_groceries.d b/05_hash_tables/d/01_price_of_groceries.d new file mode 100644 index 00000000..04f0b6b9 --- /dev/null +++ b/05_hash_tables/d/01_price_of_groceries.d @@ -0,0 +1,8 @@ +module app; + +import std; + +void main() { + float[string] book = ["apple": 0.67, "milk": 1.49, "avocado": 1.49]; + writeln(book); +} diff --git a/05_hash_tables/d/02_check_voter.d b/05_hash_tables/d/02_check_voter.d new file mode 100644 index 00000000..e7232279 --- /dev/null +++ b/05_hash_tables/d/02_check_voter.d @@ -0,0 +1,21 @@ +module app; + +import std; + +bool[string] voted; + +void check_voter(string name) { + auto p = name in voted; + if (p !is null) + writeln("Kick them out!"); + else { + voted[name] = true; + writeln("Let them vote!"); + } +} + +void main() { + check_voter("tom"); + check_voter("mike"); + check_voter("mike"); +} diff --git a/05_hash_tables/dart/01_price_of_groceries.dart b/05_hash_tables/dart/01_price_of_groceries.dart new file mode 100644 index 00000000..1aff6ad4 --- /dev/null +++ b/05_hash_tables/dart/01_price_of_groceries.dart @@ -0,0 +1,15 @@ +void main(List args) { + final book = {}; + book.addAll( + { + 'apple': 0.67, + 'milk': 1.49, + 'avocado': 1.49, + }, + ); + + print(book); + print(book['apple']); + print(book['milk']); + print(book['avocado']); +} diff --git a/05_hash_tables/dart/02_check_voter.dart b/05_hash_tables/dart/02_check_voter.dart new file mode 100644 index 00000000..b4912949 --- /dev/null +++ b/05_hash_tables/dart/02_check_voter.dart @@ -0,0 +1,16 @@ +void main(List args) { + final voted = {}; + + checkVoter('tom', voted); + checkVoter('mike', voted); + checkVoter('mike', voted); +} + +void checkVoter(String name, Map voted) { + if (voted[name] != null) { + print('Kick them out!'); + } else { + voted[name] = true; + print('Let them vote'); + } +} diff --git a/05_hash_tables/golang/02_check_voter.go b/05_hash_tables/golang/02_check_voter.go index 4da95446..296371f4 100644 --- a/05_hash_tables/golang/02_check_voter.go +++ b/05_hash_tables/golang/02_check_voter.go @@ -13,9 +13,9 @@ func main() { func check_voter(name string) { if voted[name] { - fmt.Println("kick tem out!") + fmt.Println("kick them out!") } else { voted[name] = true - fmt.Println("let tem vote!") + fmt.Println("let them vote!") } } diff --git a/05_hash_tables/javascript/02_check_voter.js b/05_hash_tables/javascript/02_check_voter.js index 288eba63..4f1c2c50 100644 --- a/05_hash_tables/javascript/02_check_voter.js +++ b/05_hash_tables/javascript/02_check_voter.js @@ -1,16 +1,20 @@ -'use strict'; +"use strict"; const voted = {}; + +/** + * Vote check + * @param {string} name Voter name + */ function check_voter(name) { if (voted[name]) { - console.log('kick them out!'); + console.log("kick them out!"); } else { voted[name] = true; - console.log('let them vote!'); + console.log("let them vote!"); } } - check_voter("tom"); // let them vote! check_voter("mike"); // let them vote! check_voter("mike"); // kick them out! diff --git a/05_hash_tables/javascript/03_hashtable.js b/05_hash_tables/javascript/03_hashtable.js index 7c02d9dd..ceaeebe5 100644 --- a/05_hash_tables/javascript/03_hashtable.js +++ b/05_hash_tables/javascript/03_hashtable.js @@ -1,173 +1,162 @@ /** * Class HashTable - * - * @param {object} obj + * @param {Object} obj */ -let HashTable = function( obj ) { - let length = 0; - this._items = ( function( obj ) { - let items = {}; - for ( let p in obj ) { - items[p] = obj[p]; - length++; - } - return items; - }( obj ) ); - - /** - * Associates the specified value to the specified key - * - * @param {string} key The key to which associate the value - * @param {string} value The value to associate to the key - * - * @return {(undefined|object)} Undefined is object didn't exists before this call - */ - this.set = function( key, value ) { - let previous = undefined; - - if ( this.has( key ) ) { - previous = this._items[key]; - } else { - length++; - } - - this._items[key] = value; - - return previous; - }; - - /** - * Returns the value associated to the specified key - * - * @param {string} key The key from which retrieve the value - * - * @return {(undefined|string)} Undefined or associated value - */ - this.get = function( key ) { - return this._items.hasOwnProperty( key ) ? this._items[key] : undefined; - }; - - /** - * Returns whether the hashtable contains the specified key - * - * @param {string} key The key to check - * - * @return {boolean} - */ - this.has = function( key ) { - return this._items.hasOwnProperty( key ); - }; - - /** - * Removes the specified key with its value - * - * @param {string} key The key to remove - * - * @return {(undefined|string)} Undefined if key doesn't exist and - * string (previous value) - value of deleted item - */ - this.remove = function( key ) { - if ( this.has( key ) ) { - let previous = this._items[key]; - length--; - delete this._items[key]; - return previous; - } else { - return undefined; - } - }; - - /** - * Returns an array with all the registered keys - * - * @return {array} - */ - this.getKeys = function() { - let keys = []; - - for ( let i in this._items ) { - if ( this.has( i ) ) { - keys.push( i ); - } - } - - return keys; - }; - - /** - * Returns an array with all the registered values - * - * @return {array} - */ - this.getValues = function() { - let values = []; - - for ( let i in this._items ) { - if ( this.has( i ) ) { - values.push( this._items[i] ); - } - } - - return values; - }; - - /** - * Iterates all entries in the specified iterator callback - * @param {function} callback A method with 2 parameters: key, value - */ - this.each = function( callback ) { - for ( let i in this._items ) { - if ( this.has( i ) ) { - callback( i, this._items[i] ); - } - } - }; - - /** - * Deletes all the key-value pairs on the hashmap - */ - this.clear = function() { - this._items = {}; - length = 0; - }; - - /** - * Gets the count of the entries in the hashtable - */ - Object.defineProperty( this, 'length', { - get: function() { - return length; - }, - }); - - /** - * Gets an array of all keys in the hashtable - */ - Object.defineProperty(this, 'keys', { - get: function() { - return this.getKeys(); - }, - }); - - /** - * Gets an array of all values in the hashtable - */ - Object.defineProperty(this, 'values', { - get: function() { - return this.getValues(); - }, - }); +const HashTable = function(obj) { + let length = 0; + this._items = (function(obj) { + let items = {}; + for (let p in obj) { + items[p] = obj[p]; + length++; + } + return items; + })(obj); + + /** + * Associates the specified value to the specified key + * @param {string} key The key to which associate the value + * @param {string} value The value to associate to the key + * @returns {(undefined|Object)} Undefined is object didn't exists before this call + */ + this.set = function(key, value) { + let previous = undefined; + + if (this.has(key)) { + previous = this._items[key]; + } else { + length++; + } + + this._items[key] = value; + + return previous; + }; + + /** + * Returns the value associated to the specified key + * @param {string} key The key from which retrieve the value + * @returns {(undefined|string)} Undefined or associated value + */ + this.get = function(key) { + return this._items.hasOwnProperty(key) ? this._items[key] : undefined; + }; + + /** + * Returns whether the hashtable contains the specified key + * @param {string} key The key to check + * @returns {boolean} + */ + this.has = function(key) { + return this._items.hasOwnProperty(key); + }; + + /** + * Removes the specified key with its value + * @param {string} key The key to remove + * @returns {(undefined|string)} Undefined if key doesn't exist and + * string (previous value) - value of deleted item + */ + this.remove = function(key) { + if (this.has(key)) { + let previous = this._items[key]; + length--; + delete this._items[key]; + return previous; + } else { + return undefined; + } + }; + + /** + * Returns an array with all the registered keys + * @returns {Array} + */ + this.getKeys = function() { + let keys = []; + + for (let i in this._items) { + if (this.has(i)) { + keys.push(i); + } + } + + return keys; + }; + + /** + * Returns an array with all the registered values + * @returns {Array} + */ + this.getValues = function() { + let values = []; + + for (let i in this._items) { + if (this.has(i)) { + values.push(this._items[i]); + } + } + + return values; + }; + + /** + * Iterates all entries in the specified iterator callback + * @param {function} callback A method with 2 parameters: key, value + */ + this.each = function(callback) { + for (let i in this._items) { + if (this.has(i)) { + callback(i, this._items[i]); + } + } + }; + + /** + * Deletes all the key-value pairs on the hashmap + */ + this.clear = function() { + this._items = {}; + length = 0; + }; + + /** + * Gets the count of the entries in the hashtable + */ + Object.defineProperty(this, "length", { + get: function() { + return length; + } + }); + + /** + * Gets an array of all keys in the hashtable + */ + Object.defineProperty(this, "keys", { + get: function() { + return this.getKeys(); + } + }); + + /** + * Gets an array of all values in the hashtable + */ + Object.defineProperty(this, "values", { + get: function() { + return this.getValues(); + } + }); }; -let hashtable = new HashTable({'one': 1, 'two': 2, 'three': 3, 'cuatro': 4}); +const hashtable = new HashTable({ one: 1, two: 2, three: 3, cuatro: 4 }); -console.log( 'Original length: ' + hashtable.length ); // Original length: 4 -console.log( 'Value of key "one": ' + hashtable.get( 'one' ) ); // Value of key "one": 1 -console.log( 'Has key "foo"? ' + hashtable.has( 'foo' )); // Has key "foo"? false -console.log( 'Previous value of key "foo": ' + hashtable.set( 'foo', 'bar' ) ); // Previous value of key "foo": undefined -console.log( 'Length after set: ' + hashtable.length ); // Length after set: 5 -console.log( 'Value of key "foo": ' + hashtable.get( 'foo' ) ); // Value of key "foo": bar -console.log( 'Value of key "cuatro": ' + hashtable.get( 'cuatro' )); // Value of key "cuatro": 4 -console.log( 'Get keys by using property: ' + hashtable.keys ); // Get keys by using property: one,two,three,cuatro,foo +console.log("Original length: " + hashtable.length); // Original length: 4 +console.log('Value of key "one": ' + hashtable.get("one")); // Value of key "one": 1 +console.log('Has key "foo"? ' + hashtable.has("foo")); // Has key "foo"? false +console.log('Previous value of key "foo": ' + hashtable.set("foo", "bar")); // Previous value of key "foo": undefined +console.log("Length after set: " + hashtable.length); // Length after set: 5 +console.log('Value of key "foo": ' + hashtable.get("foo")); // Value of key "foo": bar +console.log('Value of key "cuatro": ' + hashtable.get("cuatro")); // Value of key "cuatro": 4 +console.log("Get keys by using property: " + hashtable.keys); // Get keys by using property: one,two,three,cuatro,foo hashtable.clear(); -console.log( 'Length after clear: ' + hashtable.length ); // Length after clear: 0 +console.log("Length after clear: " + hashtable.length); // Length after clear: 0 diff --git a/05_hash_tables/julia/01_price_of_groceries.jl b/05_hash_tables/julia/01_price_of_groceries.jl new file mode 100644 index 00000000..3ddb89b7 --- /dev/null +++ b/05_hash_tables/julia/01_price_of_groceries.jl @@ -0,0 +1,2 @@ +book = Dict("apple"=> 0.67, "milk"=> 1.49, "avocado"=> 1.49) +println(book) diff --git a/05_hash_tables/julia/02_check_voter.jl b/05_hash_tables/julia/02_check_voter.jl new file mode 100644 index 00000000..700a52d6 --- /dev/null +++ b/05_hash_tables/julia/02_check_voter.jl @@ -0,0 +1,13 @@ +function check_vote(name) + if voted.get(name) + println("kick them out!") + else + voted[name] = true + println("let them vote!") + end +end + +voted = Dict() +check_vote("tom") +check_vote("mike") +check_vote("mike") diff --git a/05_hash_tables/kotlin/01_price_of_groceries.kt b/05_hash_tables/kotlin/01_price_of_groceries.kt new file mode 100644 index 00000000..e38091ff --- /dev/null +++ b/05_hash_tables/kotlin/01_price_of_groceries.kt @@ -0,0 +1,11 @@ + +fun main(args: Array) { + + val book = hashMapOf( + "apple" to 0.67, + "milk" to 1.49, + "avocado" to 1.49 + ) + + println(book) +} \ No newline at end of file diff --git a/05_hash_tables/kotlin/02_check_voter.kt b/05_hash_tables/kotlin/02_check_voter.kt new file mode 100644 index 00000000..09c9ec47 --- /dev/null +++ b/05_hash_tables/kotlin/02_check_voter.kt @@ -0,0 +1,19 @@ +val voted:HashMap = HashMap() + +fun checkVoter(name: String) { + + if(!voted.containsKey(name)){ + voted.put(name, true) + println("let them vote!") + } else { + println("kick them out!") + } + +} + +fun main(args: Array) { + + checkVoter("tom") + checkVoter("mike") + checkVoter("mike") +} \ No newline at end of file diff --git a/05_hash_tables/kotlin/readme.md b/05_hash_tables/kotlin/readme.md new file mode 100644 index 00000000..bc2c9515 --- /dev/null +++ b/05_hash_tables/kotlin/readme.md @@ -0,0 +1,14 @@ +# HOW TO: + +## Example 01: + +### Compile +`kotlinc 01_price_of_groceries.kt -include-runtime -d price_of_groceries.jar` +### Execute +`java -jar price_of_groceries.jar` + +## Example 02: +### Compile +`kotlinc 02_check_voter.kt -include-runtime -d check_voter.jar` +### Execute +`java -jar check_voter.jar` diff --git a/05_hash_tables/ruby/02_check_voter.rb b/05_hash_tables/ruby/02_check_voter.rb index 0832e526..b13f50b6 100644 --- a/05_hash_tables/ruby/02_check_voter.rb +++ b/05_hash_tables/ruby/02_check_voter.rb @@ -3,7 +3,7 @@ @voted = {} def check_voter(name) - if @voted.key?(name) && @voted[name] + if @voted[name] puts "kick them out!" else @voted[name] = true diff --git a/05_hash_tables/zig/check_voter.zig b/05_hash_tables/zig/check_voter.zig new file mode 100644 index 00000000..1cc7bc86 --- /dev/null +++ b/05_hash_tables/zig/check_voter.zig @@ -0,0 +1,22 @@ +const std = @import("std"); +const heap = std.heap; + +pub fn main() !void { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + + var map = std.StringHashMap(void).init(gpa.allocator()); + defer map.deinit(); + + try checkVoter(&map, "tom"); + try checkVoter(&map, "mike"); + try checkVoter(&map, "mike"); +} + +fn checkVoter(voted: *std.StringHashMap(void), name: []const u8) !void { + if (voted.contains(name)) { + std.debug.print("kick them out!\n", .{}); + } else { + try voted.put(name, {}); + std.debug.print("let them vote!\n", .{}); + } +} diff --git a/05_hash_tables/zig/price_of_groceries.zig b/05_hash_tables/zig/price_of_groceries.zig new file mode 100644 index 00000000..91b42a2f --- /dev/null +++ b/05_hash_tables/zig/price_of_groceries.zig @@ -0,0 +1,19 @@ +const std = @import("std"); +const heap = std.heap; + +pub fn main() !void { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + + var map = std.StringHashMap(f32).init(gpa.allocator()); + defer map.deinit(); + + try map.put("apple", 0.67); + try map.put("milk", 1.49); + try map.put("avocado", 1.49); + + var iterator = map.iterator(); + + while (iterator.next()) |entry| { + std.debug.print("{s}: {d:.2}\n", .{ entry.key_ptr.*, entry.value_ptr.* }); + } +} diff --git a/06_breadth-first_search/ES6/01_breadth-first_search.js b/06_breadth-first_search/ES6/01_breadth-first_search.js index f140373f..1767cbeb 100644 --- a/06_breadth-first_search/ES6/01_breadth-first_search.js +++ b/06_breadth-first_search/ES6/01_breadth-first_search.js @@ -1,18 +1,27 @@ -const personIsSeller = name => name[name.length - 1] === 'm'; - const graph = {}; -graph.you = ['alice', 'bob', 'claire']; -graph.bob = ['anuj', 'peggy']; -graph.alice = ['peggy']; -graph.claire = ['thom', 'jonny']; +graph.you = ["alice", "bob", "claire"]; +graph.bob = ["anuj", "peggy"]; +graph.alice = ["peggy"]; +graph.claire = ["thom", "jonny"]; graph.anuj = []; graph.peggy = []; graph.thom = []; graph.jonny = []; -const search = (name) => { - let searchQueue = []; - searchQueue = searchQueue.concat(graph[name]); +/** + * Determine whether a person is a seller + * @param {string} name Friend's name + * @returns {boolean} Result of checking + */ +const personIsSeller = name => name[name.length - 1] === "m"; + +/** + * Find a mango seller + * @param {string} name Friend's name + * @returns {boolean} Search results + */ +const search = name => { + let searchQueue = [...graph[name]]; // This array is how you keep track of which people you've searched before. const searched = []; while (searchQueue.length) { @@ -31,4 +40,4 @@ const search = (name) => { return false; }; -search('you'); // thom is a mango seller! +search("you"); // thom is a mango seller! diff --git a/06_breadth-first_search/ES6/02_breadth-first_search_by_Rytikov_Dmitrii.js b/06_breadth-first_search/ES6/02_breadth-first_search_by_Rytikov_Dmitrii.js index 5f3836c5..75f5405f 100644 --- a/06_breadth-first_search/ES6/02_breadth-first_search_by_Rytikov_Dmitrii.js +++ b/06_breadth-first_search/ES6/02_breadth-first_search_by_Rytikov_Dmitrii.js @@ -1,23 +1,35 @@ const graph = {}; -graph.you = ['alice', 'bob', 'claire']; -graph.bob = ['anuj', 'peggy']; -graph.alice = ['peggy']; -graph.claire = ['thom', 'jonny']; +graph.you = ["alice", "bob", "claire"]; +graph.bob = ["anuj", "peggy"]; +graph.alice = ["peggy"]; +graph.claire = ["thom", "jonny"]; graph.anuj = []; graph.peggy = []; graph.thom = []; -const isSeller = name => name[name.length - 1] === 'm'; +/** + * Determine whether a person is a seller + * @param {string} name Friend's name + * @returns {boolean} Result of checking + */ +const isSeller = name => name[name.length - 1] === "m"; -const search = (name, graph) => { - const iter = (waited, visited) => { - if (waited.length === 0) { - return false; - } +/** + * Find a mango seller + * @param {string} name Friend's name + * @param {Object} graph Hash table + * @returns {boolean} Search results + */ +const search = (name, graph = {}) => { + /** + * Recursive function to test people + * @param {Array} waited List of people you need to check + * @param {Set} visited List of checked people + */ + const iter = (waited = [], visited) => { + if (waited.length === 0) return false; const [current, ...rest] = waited; - if (visited.has(current)) { - return iter(rest, visited); - } + if (visited.has(current)) return iter(rest, visited); if (isSeller(current)) { console.log(`${current} is a mango seller!`); return true; @@ -29,4 +41,4 @@ const search = (name, graph) => { return iter(graph[name], new Set()); }; -search('you'); +search("you", graph); diff --git a/06_breadth-first_search/Scala Solutions b/06_breadth-first_search/Scala Solutions new file mode 100644 index 00000000..674fd85c --- /dev/null +++ b/06_breadth-first_search/Scala Solutions @@ -0,0 +1,71 @@ +package SearchAndSort + +import scala.collection.immutable.HashMap +import scala.collection.{immutable, mutable} + + +object BreadthFirstSearch extends App { + + val graph = HashMap( + ("you" -> Vector("alice", "bob", "claire")), + ("bob" -> Vector("anuj", "peggy")), + ("alice" -> Vector("peggy")), + ("claire" -> Vector("thom", "johnny")), + ("anuj" -> Vector()), + ("peggy" -> Vector()), + ("thom" -> Vector()), + ("jonny" -> Vector()), + ) + + def personIsSeller(name: String): Boolean = + name.endsWith("z") + + def search(name: String): Unit = { + var searchQue = mutable.Queue[String]() + searchQue ++= graph(name) + var searched = Array() + var seller = false + while (!seller) { + val person = searchQue.dequeue() + if (!searched.contains(person)){ + if (personIsSeller(person)) { + println(person + " is a mango seller!") + seller = true + } + else { + if (searchQue.isEmpty) { + println("No Mango Sellers") + seller = true + } + else { + searchQue ++= graph(person) + searched + person + } + } + } + + } + } + + println(search("you")) + + def searchFunctional(name: String): String = { + var searchQue = immutable.Queue[String]() + + @scala.annotation.tailrec + def helper(searchQue: immutable.Queue[String], searched: Vector[String] = Vector()): String = { + if (searchQue.length > 1) return "No Mango sellers" + val person = searchQue.dequeue._1 + if (searched.contains(person)) + helper(searchQue.tail) + else if (personIsSeller(person)) { + val result: String = s"$person is a mango seller!" + result + } else + helper(searchQue.tail ++ graph(person), searched :+ person) + } + helper(searchQue ++ graph(name)) + } + + println(searchFunctional("you")) +} diff --git a/06_breadth-first_search/c++11/01_breadth-first_search.cpp b/06_breadth-first_search/c++11/01_breadth-first_search.cpp index 2053590e..81cf7d01 100644 --- a/06_breadth-first_search/c++11/01_breadth-first_search.cpp +++ b/06_breadth-first_search/c++11/01_breadth-first_search.cpp @@ -18,9 +18,8 @@ bool search(const T& name, const std::unordered_map>& graph) { std::unordered_set searched; // add all friends to search queue - for (auto friend_name : graph.find(name) -> second) { + for (auto&& friend_name : graph.find(name) -> second) search_queue.push(friend_name); - } while (!search_queue.empty()) { T& person = search_queue.front(); @@ -32,12 +31,10 @@ bool search(const T& name, const std::unordered_map>& graph) { cout << person << " is a mango seller!" << endl; return true; } - std::vector friend_list = graph.find(person) -> second; // add all friends of a person to search queue - for (T friend_name : friend_list) { + for (auto&& friend_name : graph.find(person) -> second) search_queue.push(friend_name); - } // mark this person as searched searched.insert(person); @@ -61,4 +58,4 @@ int main() { std::string name = "you"; bool result = search(name, graph); cout << "Found mango seller: " << result << endl; -} \ No newline at end of file +} diff --git a/06_breadth-first_search/d/01_breadth_first_search.d b/06_breadth-first_search/d/01_breadth_first_search.d new file mode 100644 index 00000000..6fdae877 --- /dev/null +++ b/06_breadth-first_search/d/01_breadth_first_search.d @@ -0,0 +1,42 @@ +module app; + +import std; + +bool personIsSeller(string name) { + return name[name.length - 1] == 'm'; +} + +bool search(string name) { + auto search_queue = DList!string(); + search_queue.insertBack(name); + bool[string] searched; + while (!search_queue.empty) { + auto person = search_queue.front(); + search_queue.removeFront(); + auto found = person in searched; + if (found !is null) + continue; + if (personIsSeller(person)) { + writeln(person, " is a mango seller!"); + return true; + } + search_queue.insertBack(graph[person]); + searched[person] = true; + } + return false; +} + +string[][string] graph; + +void main() { + graph["you"] = ["alice", "bob", "claire"]; + graph["bob"] = ["anuj", "peggy"]; + graph["alice"] = ["peggy"]; + graph["claire"] = ["thom", "jonny"]; + graph["anuj"] = []; + graph["peggy"] = []; + graph["thom"] = []; + graph["jonny"] = []; + + search("you"); +} diff --git a/06_breadth-first_search/dart/01_breadth-first_search.dart b/06_breadth-first_search/dart/01_breadth-first_search.dart new file mode 100644 index 00000000..4b741c4c --- /dev/null +++ b/06_breadth-first_search/dart/01_breadth-first_search.dart @@ -0,0 +1,42 @@ +import 'dart:collection'; + +void main(List args) { + final graph = >{}; + graph.addAll( + >{ + 'you': ['alice', 'bob', 'claire'], + 'bob': ['anuj', 'peggy'], + 'alice': ['peggy'], + 'claire': ['thom', 'jonny'], + 'anuj': [], + 'peggy': [], + 'thom': [], + 'jonny': [], + }, + ); + + search(graph, 'you'); +} + +bool search(Map> graph, String name) { + final searchQueue = Queue()..addAll(graph[name] ?? []); + final searched = List.empty(growable: true); + + while (searchQueue.isNotEmpty) { + final String person = searchQueue.removeFirst(); + if (searched.contains(person) == false) { + if (_personIsSeller(person)) { + print('$person is a Mango seller!'); + return true; + } else { + searchQueue.addAll(graph[person] ?? []); + searched.add(person); + } + } + } + return false; +} + +bool _personIsSeller(String name) { + return name.endsWith('m'); +} diff --git a/06_breadth-first_search/golang/bfs.go b/06_breadth-first_search/golang/bfs.go index a3624313..274c7275 100644 --- a/06_breadth-first_search/golang/bfs.go +++ b/06_breadth-first_search/golang/bfs.go @@ -5,43 +5,36 @@ import ( ) func PersonIsSeller(name string) bool { - /* Assuming the person whose name ends with m as the mango seller as per the book */ return string(name[len(name)-1]) == "m" } -func search(name string) bool { - graph := make(map[string][]string) - graph["you"] = []string{"alice", "bob", "claire"} - graph["bob"] = []string{"anuj", "peggy"} - graph["alice"] = []string{"peggy"} - graph["claire"] = []string{"thom", "jonny"} - graph["anuj"] = []string{} - graph["peggy"] = []string{} - graph["thom"] = []string{} - graph["jonny"] = []string{} +func search(aGraph map[string][]string, name string) bool { //search queue - var search_queue []string - search_queue = append(search_queue, graph[name]...) + var searchQueue []string + searchQueue = append(searchQueue, aGraph[name]...) var searched []string - for len(search_queue) > 0 { - var person = search_queue[0] - search_queue = search_queue[1:] - var person_already_searched = false + + for len(searchQueue) > 0 { + var person = searchQueue[0] + searchQueue = searchQueue[1:] + personAlreadySearched := false + /* Checking to see if this person has already been searched */ for i := 0; i < len(searched); i++ { if searched[i] == person { - person_already_searched = true + personAlreadySearched = true } } - if person_already_searched == false { + + if personAlreadySearched == false { if PersonIsSeller(person) { - fmt.Println(person + " is the mango seller!") + fmt.Println(person, "is a mango seller!") return true } - search_queue = append(search_queue, graph[person]...) + searchQueue = append(searchQueue, aGraph[person]...) searched = append(searched, person) } @@ -51,5 +44,15 @@ func search(name string) bool { } func main() { - search("you") + graph := make(map[string][]string) + graph["you"] = []string{"alice", "bob", "claire"} + graph["bob"] = []string{"anuj", "peggy"} + graph["alice"] = []string{"peggy"} + graph["claire"] = []string{"thom", "jonny"} + graph["anuj"] = []string{} + graph["peggy"] = []string{} + graph["thom"] = []string{} + graph["jonny"] = []string{} + + search(graph, "you") } diff --git a/06_breadth-first_search/javascript/01_breadth-first_search.js b/06_breadth-first_search/javascript/01_breadth-first_search.js index c3f478f0..a4700654 100644 --- a/06_breadth-first_search/javascript/01_breadth-first_search.js +++ b/06_breadth-first_search/javascript/01_breadth-first_search.js @@ -1,7 +1,3 @@ -function person_is_seller(name) { - return name[name.length - 1] === "m"; -} - const graph = {}; graph["you"] = ["alice", "bob", "claire"]; graph["bob"] = ["anuj", "peggy"]; @@ -12,6 +8,20 @@ graph["peggy"] = []; graph["thom"] = []; graph["jonny"] = []; +/** + * Determine whether a person is a seller + * @param {string} name Friend's name + * @returns {boolean} Result of checking + */ +function personIsSeller(name) { + return name[name.length - 1] === "m"; +} + +/** + * Find a mango seller + * @param {string} name Friend's name + * @returns {boolean} Search results + */ function search(name) { let search_queue = []; search_queue = search_queue.concat(graph[name]); @@ -21,7 +31,7 @@ function search(name) { let person = search_queue.shift(); // Only search this person if you haven't already searched them if (searched.indexOf(person) === -1) { - if (person_is_seller(person)) { + if (personIsSeller(person)) { console.log(person + " is a mango seller!"); return true; } diff --git a/06_breadth-first_search/javascript/02_breadth-first_search_recursion.js b/06_breadth-first_search/javascript/02_breadth-first_search_recursion.js new file mode 100644 index 00000000..c08be6c3 --- /dev/null +++ b/06_breadth-first_search/javascript/02_breadth-first_search_recursion.js @@ -0,0 +1,48 @@ +const graph = {}; +graph["you"] = ["alice", "bob", "claire"]; +graph["bob"] = ["anuj", "peggy"]; +graph["alice"] = ["peggy"]; +graph["claire"] = ["thom", "jonny"]; +graph["anuj"] = []; +graph["peggy"] = []; +graph["thom"] = []; +graph["jonny"] = []; + +/** + * Determine whether a person is a seller + * @param {string} name Friend's name + * @returns {boolean} Result of checking + */ +function personIsSeller(name) { + return name[name.length - 1] === "m"; +} + +/** + * Find a mango seller + * @param {string} name Friend's name + * @param {Object} graph Hash table + * @returns {boolean} Search results + */ +function search(name, graph) { + graph = graph || {}; + /** + * Recursive function to check people + * @param {Array} waited List of people you need to check + * @param {Array} visited List of checked people + */ + function inner(waited, visited) { + waited = waited || []; + if (waited.length === 0) return false; + const person = waited[0]; + const waitedCloned = waited.slice(1); + if (visited.indexOf(person) !== -1) return inner(waitedCloned, visited); + if (personIsSeller(person)) { + console.log(person + " is a mango seller!"); + return true; + } + return inner(waitedCloned.concat(graph[person]), visited.concat(person)); + } + return inner(graph[name], []); +} + +search("you", graph); diff --git a/06_breadth-first_search/julia/01_breadth-first_search.jl b/06_breadth-first_search/julia/01_breadth-first_search.jl new file mode 100644 index 00000000..4fa3c1bc --- /dev/null +++ b/06_breadth-first_search/julia/01_breadth-first_search.jl @@ -0,0 +1,39 @@ +using DataStructures, Test, Suppressor + +graph = Dict() +graph["you"] = ["alice","bob","claire"] +graph["bob"] = ["anuj","peggy"] +graph["claire"] = ["thom","jonny"] +graph["alice"] = ["peggy"] +graph["anuj"] = [] +graph["peggy"] = [] +graph["thom"] = [] +graph["jonny"] = [] + +function person_is_seller(name) + return name[end] == 'm' +end + +function search(name) + search_queue = Deque{String}() + map(n -> push!(search_queue,n),graph[name]) + searched = [] + while isempty(search_queue) == false + person = popfirst!(search_queue) + if (person in searched) == false + if person_is_seller(person) + println(person , " is a mango seller") + return true + else + map(n -> push!(search_queue,n),graph[person]) + push!(searched,person) + end + end + end + return false +end + + +result = @capture_out search("you") +@test result == "thom is a mango seller +" diff --git a/06_breadth-first_search/kotlin/01_breadth-first_search.kt b/06_breadth-first_search/kotlin/01_breadth-first_search.kt new file mode 100644 index 00000000..e8ffbfb1 --- /dev/null +++ b/06_breadth-first_search/kotlin/01_breadth-first_search.kt @@ -0,0 +1,29 @@ +import java.util.* + +val graph = hashMapOf( + "You" to listOf("Sergey", "Viktoria"), + "Viktoria" to listOf("Sergey", "Vladimir"), + "Vladimir" to listOf("Sergey", "Andrew", "Nikita", "Boris") +) + +private fun breadthFirstSearch(name: String) { + val queue = ArrayDeque(graph[name]) + val searched = arrayListOf() + while (queue.isNotEmpty()) { + val person = queue.poll() + if (!searched.contains(person)) { + if (personIsSeller(person)) { + println("$person is a mango seller!") + return + } else { + graph[person]?.let { queue.addAll(it) } + searched.add(person) + } + } + } + println("No mango sellers found!") +} + +private fun personIsSeller(name: String): Boolean = name.endsWith("s") + +fun main(args: Array) = println(breadthFirstSearch("You")) \ No newline at end of file diff --git a/06_breadth-first_search/kotlin/BreadthFirstSearch.kt b/06_breadth-first_search/kotlin/BreadthFirstSearch.kt deleted file mode 100644 index be7ea6f8..00000000 --- a/06_breadth-first_search/kotlin/BreadthFirstSearch.kt +++ /dev/null @@ -1,50 +0,0 @@ -typealias Graph = MutableMap> - -fun Graph.breadthFirstSearch(key: V, isSearched: (V) -> Boolean): Boolean { - val queue: Deque = LinkedList() - this[key]?.let { queue += it } - val searched = HashSet() - while (queue.isNotEmpty()) { - val value = queue.pop() - if (!searched.contains(value)) - if (isSearched(value)) { - println("value $value is here!") - return true - } else { - this[value]?.let { queue += it } - searched.add(value) - } - } - return false -} - -data class Person( - val name: String, - val isSellerMango: Boolean = false -) { - override fun equals(other: Any?): Boolean = - if (other is Person) other.name == name - else false - - - override fun hashCode(): Int { - return name.length - } -} - -fun main(args: Array) { - - val graph: Graph = HashMap() - - (graph as java.util.HashMap>).apply { - put(Person("John"), listOf(Person("Sergey"), Person("Viktoria"))) - put(Person("Viktoria"), listOf(Person("Sergey"), Person("Phara"))) - put(Person("Phara"), listOf(Person("Sergey"), Person("Thrall"), Person("Xul"), Person("Juncart", true))) - } - - println( - graph.breadthFirstSearch(Person("John"), Person::isSellerMango) - ) - - -} \ No newline at end of file diff --git a/06_breadth-first_search/python/01_breadth-first_search.py b/06_breadth-first_search/python/01_breadth-first_search.py index 4fefda87..0624f4ea 100644 --- a/06_breadth-first_search/python/01_breadth-first_search.py +++ b/06_breadth-first_search/python/01_breadth-first_search.py @@ -15,20 +15,20 @@ def person_is_seller(name): def search(name): search_queue = deque() - search_queue += graph[name] - # This array is how you keep track of which people you've searched before. - searched = [] + search_queue += [name] + # This is how you keep track of which people you've searched before. + searched = set() while search_queue: person = search_queue.popleft() # Only search this person if you haven't already searched them. - if person not in searched: - if person_is_seller(person): - print(person + " is a mango seller!") - return True - else: - search_queue += graph[person] - # Marks this person as searched - searched.append(person) + if person in searched: + continue + if person_is_seller(person): + print(person + " is a mango seller!") + return True + search_queue += graph[person] + # Marks this person as searched + searched.add(person) return False search("you") diff --git a/06_breadth-first_search/ruby/01_breadth-first_search.rb b/06_breadth-first_search/ruby/01_breadth-first_search.rb index cb21b9fe..4436019c 100644 --- a/06_breadth-first_search/ruby/01_breadth-first_search.rb +++ b/06_breadth-first_search/ruby/01_breadth-first_search.rb @@ -1,40 +1,39 @@ -def person_is_seller(name) +def person_is_seller?(name) name[-1] == "m" end -@graph = {} +class Graph < Hash + def search(name) + search_queue = [] + search_queue += self[name] + # The "searched" Hash is how you keep track of which people you've searched before. We use a hash because hash lookups are fast! + searched = {} -# %w(string1 string2 ...) is a shorter way to define arrays of strings -@graph["you"] = %w(alice bob claire) -@graph["bob"] = %w(anuj peggy) -@graph["alice"] = %w(peggy) -@graph["claire"] = %w(thom jonny) -@graph["anuj"] = [] -@graph["peggy"] = [] -@graph["thom"] = [] -@graph["jonny"] = [] - -def search(name) - search_queue = [] - search_queue += @graph[name] - # This array is how you keep track of which people you've searched before. - searched = [] - - until search_queue.empty? - person = search_queue.shift - # Only search this person if you haven't already searched them. - next if searched.member?(person) - if person_is_seller(person) - puts "#{person} is a mango seller!" - return true - else - search_queue += @graph[person] + until search_queue.empty? + person = search_queue.shift + # Only search this person if you haven't already searched them. + next if searched[person] + return person if yield person + search_queue += self[person] # Marks this person as searched - searched.push(person) + searched[person] = true end - end - false + false + end end -search("you") + +# %w(string1 string2 ...) is a shorter way to define arrays of strings +graph = Graph.new +graph["you"] = %w(alice bob claire) +graph["bob"] = %w(anuj peggy) +graph["alice"] = %w(peggy) +graph["claire"] = %w(thom jonny) +graph["anuj"] = [] +graph["peggy"] = [] +graph["thom"] = [] +graph["jonny"] = [] + +# we begin the search from vertex "you" and pass the match criterion in the block, then we tap the search result +graph.search("you"){|person| person_is_seller?(person)}.tap{|person| puts "#{person} is a mango seller!" if person} diff --git a/06_breadth-first_search/rust/Cargo.lock b/06_breadth-first_search/rust/Cargo.lock new file mode 100644 index 00000000..3c57ea9e --- /dev/null +++ b/06_breadth-first_search/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "breadth_first" +version = "0.1.0" diff --git a/06_breadth-first_search/rust/Cargo.toml b/06_breadth-first_search/rust/Cargo.toml new file mode 100644 index 00000000..7fa294fc --- /dev/null +++ b/06_breadth-first_search/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "breadth_first" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/06_breadth-first_search/rust/src/main.rs b/06_breadth-first_search/rust/src/main.rs new file mode 100644 index 00000000..936cb6bd --- /dev/null +++ b/06_breadth-first_search/rust/src/main.rs @@ -0,0 +1,68 @@ +use std::collections::{HashMap, VecDeque}; +use std::fmt; + +#[derive(Eq, Hash, PartialEq)] +struct Person(String); + +impl Person { + fn is_seller(&self) -> bool { + self.0.ends_with('m') + } +} + +impl fmt::Display for Person { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.0) + } +} + +fn search(graph: &HashMap<&Person, Vec<&Person>>, start: &Person) { + let mut search_queue = VecDeque::new(); + search_queue.push_back(start); + + let mut searched: Vec<&Person> = Vec::with_capacity(graph.len()); + loop { + match search_queue.pop_front() { + Some(person) => { + if !searched.contains(&person) { + if person.is_seller() { + println!("{} is a mango seller!", person); + break; + } else { + for p in graph.get(&person).unwrap() { + search_queue.push_back(p); + searched.push(person); + } + } + } + } + None => { + println!("no mango seller found!"); + break; + } + } + } +} + +fn main() { + let you = Person("you".to_string()); + let alice = Person("alice".to_string()); + let bob = Person("bob".to_string()); + let claire = Person("claire".to_string()); + let anuj = Person("anuj".to_string()); + let peggy = Person("peggy".to_string()); + let thom = Person("thom".to_string()); + let jonny = Person("jonny".to_string()); + + let mut graph = HashMap::new(); + graph.insert(&you, vec![&alice, &bob, &claire]); + graph.insert(&bob, vec![&anuj, &peggy]); + graph.insert(&alice, vec![&peggy]); + graph.insert(&claire, vec![&thom, &jonny]); + graph.insert(&anuj, vec![]); + graph.insert(&peggy, vec![]); + graph.insert(&thom, vec![]); + graph.insert(&jonny, vec![]); + + search(&graph, &you); +} diff --git a/06_breadth-first_search/zig/breadth_first_search.zig b/06_breadth-first_search/zig/breadth_first_search.zig new file mode 100644 index 00000000..c3b84cc9 --- /dev/null +++ b/06_breadth-first_search/zig/breadth_first_search.zig @@ -0,0 +1,107 @@ +const std = @import("std"); +const mem = std.mem; +const heap = std.heap; + +pub fn main() !void { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + + var graph = std.StringHashMap([][]const u8).init(gpa.allocator()); + defer graph.deinit(); + + var you = [_][]const u8{ "alice", "bob", "claire" }; + var bob = [_][]const u8{ "anuj", "peggy" }; + var alice = [_][]const u8{"peggy"}; + var claire = [_][]const u8{ "thom", "jonny" }; + var anuj = [_][]const u8{}; + var peggy = [_][]const u8{}; + var thom = [_][]const u8{}; + var jonny = [_][]const u8{}; + + try graph.put("you", &you); + try graph.put("bob", &bob); + try graph.put("alice", &alice); + try graph.put("claire", &claire); + try graph.put("anuj", &anuj); + try graph.put("peggy", &peggy); + try graph.put("thom", &thom); + try graph.put("jonny", &jonny); + + try search(gpa.allocator(), &graph, "you"); +} + +fn search( + allocator: mem.Allocator, + graph: *std.StringHashMap([][]const u8), + name: []const u8, +) !void { + var arena = heap.ArenaAllocator.init(allocator); + defer arena.deinit(); + var searched = std.BufSet.init(arena.allocator()); + const Q = std.DoublyLinkedList([]const u8); + var queue = Q{}; + + const name_edges = graph.get(name); + if (name_edges) |edges| { + var nodes = try arena.allocator().alloc(Q.Node, edges.len); + var i: usize = 0; + while (i < edges.len) : (i += 1) { + nodes[i].data = edges[i]; + } + for (nodes) |*node| { + queue.append(node); + } + } + + while (queue.len > 0) { + const person = queue.popFirst() orelse unreachable; // we always have at least one node if len > 0 + if (searched.contains(person.data)) { + continue; + } + if (personIsSeller(person.data)) { + std.debug.print("{s} is a mango seller!\n", .{person.data}); + return; + } + const ee = graph.get(person.data); + if (ee) |edges| { + var nodes = try arena.allocator().alloc(Q.Node, edges.len); + var i: usize = 0; + while (i < edges.len) : (i += 1) { + nodes[i].data = edges[i]; + } + for (nodes) |*node| { + queue.append(node); + } + } + try searched.insert(person.data); + } +} + +fn personIsSeller(name: []const u8) bool { + return name[name.len - 1] == 'm'; +} + +test "search" { + const allocator = std.testing.allocator; + var graph = std.StringHashMap([][]const u8).init(allocator); + defer graph.deinit(); + + var you = [_][]const u8{ "alice", "bob", "claire" }; + var bob = [_][]const u8{ "anuj", "peggy" }; + var alice = [_][]const u8{"peggy"}; + var claire = [_][]const u8{ "thom", "jonny" }; + var anuj = [_][]const u8{}; + var peggy = [_][]const u8{}; + var thom = [_][]const u8{}; + var jonny = [_][]const u8{}; + + try graph.put("you", &you); + try graph.put("bob", &bob); + try graph.put("alice", &alice); + try graph.put("claire", &claire); + try graph.put("anuj", &anuj); + try graph.put("peggy", &peggy); + try graph.put("thom", &thom); + try graph.put("jonny", &jonny); + + try search(allocator, &graph, "you"); +} diff --git a/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.vscode/launch.json b/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.vscode/launch.json deleted file mode 100644 index df95188b..00000000 --- a/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.vscode/launch.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": ".NET Core Launch (console)", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - "program": "${workspaceRoot}/bin/Debug/netcoreapp1.0/01_dijkstras_algorithm.dll", - "args": [], - "cwd": "${workspaceRoot}", - "externalConsole": false, - "stopAtEntry": false, - "internalConsoleOptions": "openOnSessionStart" - }, - { - "name": ".NET Core Attach", - "type": "coreclr", - "request": "attach", - "processId": "${command.pickProcess}" - } - ] -} \ No newline at end of file diff --git a/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.vscode/tasks.json b/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.vscode/tasks.json deleted file mode 100644 index adc66239..00000000 --- a/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.vscode/tasks.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "version": "0.1.0", - "command": "dotnet", - "isShellCommand": true, - "args": [], - "tasks": [ - { - "taskName": "build", - "args": [ - "${workspaceRoot}/project.json" - ], - "isBuildCommand": true, - "problemMatcher": "$msCompile" - } - ] -} \ No newline at end of file diff --git a/07_trees/csharp/01_filesystem_dfs/Program.cs b/07_trees/csharp/01_filesystem_dfs/Program.cs new file mode 100644 index 00000000..f2b2da1d --- /dev/null +++ b/07_trees/csharp/01_filesystem_dfs/Program.cs @@ -0,0 +1,37 @@ +using System; +using System.IO; +using System.Linq; + +namespace ConsoleApplication +{ + public class Program + { + public static void Main(string[] args) + { + string dir = Path.Combine(Directory.GetCurrentDirectory(), "pics"); + + PrintNames(dir); + } + + private static void PrintNames(string dir) + { + var filesAndDirs = Directory.GetFileSystemEntries(dir).OrderBy(f => f, StringComparer.OrdinalIgnoreCase); + + // loop through every file and folder in the current folder + foreach (var path in filesAndDirs) + { + if (File.Exists(path)) + { + // if it is a file, print out the name + Console.WriteLine(Path.GetFileName(path)); + } + else + { + // if it is a folder, call this function recursively on it + // to look for files and folders + PrintNames(path); + } + } + } + } +} \ No newline at end of file diff --git a/07_trees/d/01_filesystem_dfs.d b/07_trees/d/01_filesystem_dfs.d new file mode 100644 index 00000000..1974b49e --- /dev/null +++ b/07_trees/d/01_filesystem_dfs.d @@ -0,0 +1,19 @@ +module app; + +import std; + +void printnames(string dir) +{ + foreach(DirEntry name; dirEntries(dir, SpanMode.shallow)) + { + if (name.isFile) + writeln(name); + else + printnames(name); + } +} + +void main() +{ + printnames("test1"); +} diff --git a/07_trees/python/01_filesystem_dfs.py b/07_trees/python/01_filesystem_dfs.py new file mode 100644 index 00000000..052709a8 --- /dev/null +++ b/07_trees/python/01_filesystem_dfs.py @@ -0,0 +1,18 @@ +from os import listdir +from os.path import isfile, join + + +def printnames(dir): + # loop through every file and folder in the current folder + for file in sorted(listdir(dir)): + fullpath = join(dir, file) + if isfile(fullpath): + # if it is a file, print out the name + print(file) + else: + # if it is a folder, call this function recursively on it + # to look for files and folders + printnames(fullpath) + + +printnames("pics") diff --git a/08_greedy_algorithms/csharp/01_set_covering/.vscode/launch.json b/08_greedy_algorithms/csharp/01_set_covering/.vscode/launch.json deleted file mode 100644 index d033d6f1..00000000 --- a/08_greedy_algorithms/csharp/01_set_covering/.vscode/launch.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": ".NET Core Launch (console)", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - "program": "${workspaceRoot}/bin/Debug/netcoreapp1.0/01_set_covering.dll", - "args": [], - "cwd": "${workspaceRoot}", - "externalConsole": false, - "stopAtEntry": false, - "internalConsoleOptions": "openOnSessionStart" - }, - { - "name": ".NET Core Attach", - "type": "coreclr", - "request": "attach", - "processId": "${command.pickProcess}" - } - ] -} \ No newline at end of file diff --git a/08_greedy_algorithms/csharp/01_set_covering/.vscode/tasks.json b/08_greedy_algorithms/csharp/01_set_covering/.vscode/tasks.json deleted file mode 100644 index adc66239..00000000 --- a/08_greedy_algorithms/csharp/01_set_covering/.vscode/tasks.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "version": "0.1.0", - "command": "dotnet", - "isShellCommand": true, - "args": [], - "tasks": [ - { - "taskName": "build", - "args": [ - "${workspaceRoot}/project.json" - ], - "isBuildCommand": true, - "problemMatcher": "$msCompile" - } - ] -} \ No newline at end of file diff --git a/08_greedy_algorithms/javascript/01_set_covering.js b/08_greedy_algorithms/javascript/01_set_covering.js deleted file mode 100644 index a2bb41ef..00000000 --- a/08_greedy_algorithms/javascript/01_set_covering.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -// You pass an array in, and it gets converted to a set. -let states_needed = new Set(["mt", "wa", "or", "id", "nv", "ut", "ca", "az"]); - -const stations = {}; -stations["kone"] = new Set(["id", "nv", "ut"]); -stations["ktwo"] = new Set(["wa", "id", "mt"]); -stations["kthree"] = new Set(["or", "nv", "ca"]); -stations["kfour"] = new Set(["nv", "ut"]); -stations["kfive"] = new Set(["ca", "az"]); - -const final_stations = new Set(); - - -while (states_needed.size) { - let best_station = null; - let states_covered = new Set(); - for (let station in stations) { - let states = stations[station]; - let covered = new Set([...states_needed].filter((x) => states.has(x))); - if (covered.size > states_covered.size) { - best_station = station; - states_covered = covered; - } - } - states_needed = new Set([...states_needed].filter((x) => !states_covered.has(x))); - final_stations.add(best_station); -} - -console.log(final_stations); // Set { 'kone', 'ktwo', 'kthree', 'kfive' } diff --git a/08_greedy_algorithms/python/01_set_covering.py b/08_greedy_algorithms/python/01_set_covering.py deleted file mode 100644 index bbd1b5ff..00000000 --- a/08_greedy_algorithms/python/01_set_covering.py +++ /dev/null @@ -1,25 +0,0 @@ -# You pass an array in, and it gets converted to a set. -states_needed = set(["mt", "wa", "or", "id", "nv", "ut", "ca", "az"]) - -stations = {} -stations["kone"] = set(["id", "nv", "ut"]) -stations["ktwo"] = set(["wa", "id", "mt"]) -stations["kthree"] = set(["or", "nv", "ca"]) -stations["kfour"] = set(["nv", "ut"]) -stations["kfive"] = set(["ca", "az"]) - -final_stations = set() - -while states_needed: - best_station = None - states_covered = set() - for station, states in stations.items(): - covered = states_needed & states - if len(covered) > len(states_covered): - best_station = station - states_covered = covered - - states_needed -= states_covered - final_stations.add(best_station) - -print(final_stations) diff --git a/07_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js b/09_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js similarity index 76% rename from 07_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js rename to 09_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js index 1516bb16..396f7fe8 100644 --- a/07_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js +++ b/09_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js @@ -21,21 +21,25 @@ costs.fin = Infinity; // the parents table const parents = {}; -parents.a = 'start'; -parents.b = 'start'; +parents.a = "start"; +parents.b = "start"; parents.fin = null; let processed = []; - -const findLowestCostNode = (itCosts) => { +/** + * Find the lowest node + * @param {Object} itCosts Hash table + * @returns {(string|null)} The lowest node + */ +const findLowestCostNode = itCosts => { let lowestCost = Infinity; let lowestCostNode = null; - Object.keys(itCosts).forEach((node) => { + Object.keys(itCosts).forEach(node => { const cost = itCosts[node]; // If it's the lowest cost so far and hasn't been processed yet... - if (cost < lowestCost && (processed.indexOf(node) === -1)) { + if (cost < lowestCost && !processed.includes(node)) { // ... set it as the new lowest-cost node. lowestCost = cost; lowestCostNode = node; @@ -50,7 +54,7 @@ while (node !== null) { const cost = costs[node]; // Go through all the neighbors of this node const neighbors = graph[node]; - Object.keys(neighbors).forEach((n) => { + Object.keys(neighbors).forEach(n => { const newCost = cost + neighbors[n]; // If it's cheaper to get to this neighbor by going through this node if (costs[n] > newCost) { @@ -62,11 +66,11 @@ while (node !== null) { }); // Mark the node as processed - processed = processed.concat(node); + processed.push(node); // Find the next node to process, and loop node = findLowestCostNode(costs); } -console.log('Cost from the start to each node:'); +console.log("Cost from the start to each node:"); console.log(costs); // { a: 5, b: 2, fin: 6 } diff --git a/09_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go b/09_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go new file mode 100644 index 00000000..0a5fa3c0 --- /dev/null +++ b/09_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go @@ -0,0 +1,94 @@ +package main + +import ( + "fmt" + "math" +) + +var graph map[string]map[string]float64 +var costs map[string]float64 +var parents map[string]string +var processed []string + +func main() { + // the graph + graph = make(map[string]map[string]float64) + graph["start"] = make(map[string]float64) + graph["start"]["a"] = 6 + graph["start"]["b"] = 2 + + graph["a"] = make(map[string]float64) + graph["a"]["fin"] = 1 + + graph["b"] = make(map[string]float64) + graph["b"]["a"] = 3 + graph["b"]["fin"] = 5 + + graph["fin"] = make(map[string]float64) + + // the costs table + costs = make(map[string]float64) + costs["a"] = 6 + costs["b"] = 2 + costs["fin"] = math.Inf(1) + + // the parents table + parents = make(map[string]string) + parents["a"] = "start" + parents["b"] = "start" + parents["fin"] = "" + + // Find the lowest-cost node that you haven't processed yet. + node := find_lowest_cost_node(costs) + // If you've processed all the nodes, this while loop is done. + + for node != "" { + cost := costs[node] + // Go through all the neighbors of this node. + neighbors := graph[node] + + for node := range neighbors { + new_cost := cost + neighbors[node] + // If it's cheaper to get to this neighbor by going through this node... + if costs[node] > new_cost { + // ... update the cost for this node. + costs[node] = new_cost + // This node becomes the new parent for this neighbor. + parents[node] = node + } + } + // Mark the node as processed. + processed = append(processed, node) + // Find the next node to process, and loop. + node = find_lowest_cost_node(costs) + } + + fmt.Println(costs) + +} + +func find_lowest_cost_node(costs map[string]float64) string { + lowest_cost := math.Inf(1) + lowest_cost_node := "" + + for node := range costs { + // fmt.Println("Node:", node, "Value:", value) + cost := costs[node] + // If it's the lowest cost so far and hasn't been processed yet... + if cost < lowest_cost && !contains(processed, node) { + // ... set it as the new lowest-cost node. + lowest_cost = cost + lowest_cost_node = node + } + } + return lowest_cost_node +} + +func contains(s []string, e string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} diff --git a/07_dijkstras_algorithm/Haskell/01_dijkstras_algorithm.hs b/09_dijkstras_algorithm/Haskell/01_dijkstras_algorithm.hs similarity index 100% rename from 07_dijkstras_algorithm/Haskell/01_dijkstras_algorithm.hs rename to 09_dijkstras_algorithm/Haskell/01_dijkstras_algorithm.hs diff --git a/07_dijkstras_algorithm/PowerShell/01_dijkstras_algorithm.ps1 b/09_dijkstras_algorithm/PowerShell/01_dijkstras_algorithm.ps1 similarity index 100% rename from 07_dijkstras_algorithm/PowerShell/01_dijkstras_algorithm.ps1 rename to 09_dijkstras_algorithm/PowerShell/01_dijkstras_algorithm.ps1 diff --git a/09_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp b/09_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp new file mode 100644 index 00000000..1d04a6d1 --- /dev/null +++ b/09_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include + +int main(void) +{ + using node_t = std::string; + using node_cost_t = std::unordered_map; + using graph_t = std::unordered_map; + using parent_graph_t = std::unordered_map; + + // Setup graph + graph_t graph; + graph.reserve(4U); + graph.emplace("start", node_cost_t{{"a", 6}, {"b", 2}}); + graph.emplace("a", node_cost_t{{"finish", 1}}); + graph.emplace("b", node_cost_t{{"a", 3},{"finish", 5}}); + graph.emplace("finish", node_cost_t{}); + // Setup costs table + node_cost_t costs{{"a", 6},{"b", 2},{"finish", std::numeric_limits::max()}}; + // Setup parents table + parent_graph_t parents{{"a", "start"}, {"b", "start"}}; + + // A vector of processed nodes + std::vector processed; + processed.reserve(3U); + // A lambda function to find the lowest cost node + const auto find_lowest_cost_node = [&processed](const node_cost_t& costs) + { + auto lowest_cost = std::numeric_limits::max(); + node_t lowest_cost_node{}; + // Go through each node in the costs graph + for (const auto& nodeCost : costs) + { + const auto& cost = nodeCost.second; + const auto& node = nodeCost.first; + // Check if this node is processed or not; + bool isNotProcessed = std::find(processed.cbegin(), processed.cend(), node) == processed.cend(); + // Find the lowest cost node + if (cost < lowest_cost && isNotProcessed) + { + lowest_cost = cost; + lowest_cost_node = node; + } + } + return lowest_cost_node; + }; + + // node is "b" at this time + auto node = find_lowest_cost_node(costs); + while (!node.empty()) + { + const auto costSoFar = costs[node]; + const auto& neighbours = graph[node]; + // Loop through all the nodes + for (const auto& neighbour : neighbours) + { + const auto newCost = costSoFar + neighbour.second; + const auto& currentNeighbourName = neighbour.first; + // If it is cheaper than the cost registered in the costs graph, update the costs graph + if (newCost < costs[currentNeighbourName]) + { + costs[currentNeighbourName] = newCost; + parents[currentNeighbourName] = node; + } + } + // Mark the current node as processed + processed.push_back(node); + // Find the next node to process. If they are all processed, this will return an empty string. + node = find_lowest_cost_node(costs); + } + std::cout << "Cost from the start to each node:" << std::endl; + // prints finish 6 b 2 a 5 + for (const auto& cost : costs) + { + std::cout << cost.first << " " << cost.second << std::endl; + } + return 0; +} diff --git a/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.gitignore b/09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.gitignore similarity index 100% rename from 07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.gitignore rename to 09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.gitignore diff --git a/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/Program.cs b/09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/Program.cs similarity index 100% rename from 07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/Program.cs rename to 09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/Program.cs diff --git a/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/project.json b/09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/project.json similarity index 100% rename from 07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/project.json rename to 09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/project.json diff --git a/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/project.lock.json b/09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/project.lock.json similarity index 100% rename from 07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/project.lock.json rename to 09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/project.lock.json diff --git a/09_dijkstras_algorithm/d/01_dijkstras_algorithm.d b/09_dijkstras_algorithm/d/01_dijkstras_algorithm.d new file mode 100644 index 00000000..be548ea4 --- /dev/null +++ b/09_dijkstras_algorithm/d/01_dijkstras_algorithm.d @@ -0,0 +1,63 @@ +module app; + +import std; + +alias Costs = double[string]; +alias Graph = Costs[string]; + +Graph graph; +string[] processed; + +string find_lowest_cost_node(const Costs costs) +{ + double lowestCost = double.infinity; + string lowestCostNode; + foreach(node; costs.byPair) + { + auto cost = node.value; + if (cost < lowestCost && (!processed.canFind(node.key))) + { + lowestCost = cost; + lowestCostNode = node.key; + } + } + return lowestCostNode; +} + +void main() +{ + graph["start"] = ["a": 6, "b": 2]; + graph["a"] = ["finish": 1]; + graph["b"] = ["a": 3, "finish": 5]; + graph["finish"] = new Costs; + + Costs costs; + costs["a"] = 6; + costs["b"] = 2; + costs["finish"] = double.infinity; + + string[string] parents; + parents["a"] = "start"; + parents["b"] = "start"; + + auto node = find_lowest_cost_node(costs); + while (!node.empty) + { + double cost = costs[node]; + auto neighbors = graph[node]; + foreach(n; neighbors.byKey()) + { + double newCost = cost + neighbors[n]; + if (costs[n] > newCost) + { + costs[n] = newCost; + parents[n] = node; + } + } + processed ~= node; + node = find_lowest_cost_node(costs); + } + + writeln("Cost from the start to each node:"); + writeln(costs); +} diff --git a/09_dijkstras_algorithm/dart/01_djikstra_algorithm.dart b/09_dijkstras_algorithm/dart/01_djikstra_algorithm.dart new file mode 100644 index 00000000..35612870 --- /dev/null +++ b/09_dijkstras_algorithm/dart/01_djikstra_algorithm.dart @@ -0,0 +1,72 @@ +void main(List args) { + final graph = >{}..addAll( + { + 'start': { + 'a': 6, + 'b': 2, + }, + 'a': { + 'end': 1, + }, + 'b': { + 'a': 3, + 'end': 5, + }, + 'end': {}, + }, + ); + + final costs = { + 'a': 6, + 'b': 2, + 'end': double.infinity, + }; + + final parents = { + 'a': 'start', + 'b': 'start', + 'end': null, + }; + + djikstra(graph, costs, parents); + print(graph); + print(costs); + print(parents); +} + +void djikstra( + Map> graph, + Map costs, + Map parents, +) { + final processeds = []; + String? node = findTheCheapestOne(costs, processeds); + + while (node != null) { + final cost = costs[node]; + final neighbors = graph[node]; + for (String neighbor in neighbors!.keys) { + final double newCost = cost! + neighbors[neighbor]!; + if (costs[neighbor]! > newCost) { + costs[neighbor] = newCost; + parents[neighbor] = node; + } + } + processeds.add(node); + node = findTheCheapestOne(costs, processeds); + } +} + +String? findTheCheapestOne(Map costs, List processed) { + double cheapestCost = double.infinity; + String? cheapestNode; + + for (String node in costs.keys) { + final double cost = costs[node]!; + if (cost < cheapestCost && !processed.contains(node)) { + cheapestCost = cost; + cheapestNode = node; + } + } + return cheapestNode; +} diff --git a/07_dijkstras_algorithm/elixir/01_dijkstras_algorithm.exs b/09_dijkstras_algorithm/elixir/01_dijkstras_algorithm.exs similarity index 100% rename from 07_dijkstras_algorithm/elixir/01_dijkstras_algorithm.exs rename to 09_dijkstras_algorithm/elixir/01_dijkstras_algorithm.exs diff --git a/07_dijkstras_algorithm/java/01_dijkstras_algorithm/src/DijkstrasAlgorithm.java b/09_dijkstras_algorithm/java/01_dijkstras_algorithm/src/DijkstrasAlgorithm.java similarity index 100% rename from 07_dijkstras_algorithm/java/01_dijkstras_algorithm/src/DijkstrasAlgorithm.java rename to 09_dijkstras_algorithm/java/01_dijkstras_algorithm/src/DijkstrasAlgorithm.java diff --git a/07_dijkstras_algorithm/javascript/01_dijkstras_algorithm.js b/09_dijkstras_algorithm/javascript/01_dijkstras_algorithm.js similarity index 61% rename from 07_dijkstras_algorithm/javascript/01_dijkstras_algorithm.js rename to 09_dijkstras_algorithm/javascript/01_dijkstras_algorithm.js index 97cc23a1..946ef447 100644 --- a/07_dijkstras_algorithm/javascript/01_dijkstras_algorithm.js +++ b/09_dijkstras_algorithm/javascript/01_dijkstras_algorithm.js @@ -1,4 +1,4 @@ -'use strict'; +"use strict"; // the graph const graph = {}; @@ -17,44 +17,48 @@ graph["fin"] = {}; // The costs table const costs = {}; -costs['a'] = 6; -costs['b'] = 2; -costs['fin'] = Infinity; +costs["a"] = 6; +costs["b"] = 2; +costs["fin"] = Infinity; // the parents table const parents = {}; -parents['a'] = 'start'; -parents['b'] = 'start'; -parents['fin'] = null; +parents["a"] = "start"; +parents["b"] = "start"; +parents["fin"] = null; let processed = []; - -function find_lowest_cost_node(costs) { - let lowest_cost = Infinity; - let lowest_cost_node = null; +/** + * Find the lowest node + * @param {Object} itCosts Hash table + * @returns {(string|null)} The lowest node + */ +function findLowestCostNode(costs) { + let lowestCost = Infinity; + let lowestCostNode = null; // Go through each node for (let node in costs) { - let cost = costs[node]; + const cost = costs[node]; // If it's the lowest cost so far and hasn't been processed yet... - if (cost < lowest_cost && (processed.indexOf(node) === -1)) { + if (cost < lowestCost && processed.indexOf(node) === -1) { // ... set it as the new lowest-cost node. - lowest_cost = cost; - lowest_cost_node = node; + lowestCost = cost; + lowestCostNode = node; } } - return lowest_cost_node; + return lowestCostNode; } -let node = find_lowest_cost_node(costs); +let node = findLowestCostNode(costs); while (node !== null) { - let cost = costs[node]; + const cost = costs[node]; // Go through all the neighbors of this node - let neighbors = graph[node]; + const neighbors = graph[node]; Object.keys(neighbors).forEach(function(n) { - let new_cost = cost + neighbors[n]; + const new_cost = cost + neighbors[n]; // If it's cheaper to get to this neighbor by going through this node if (costs[n] > new_cost) { // ... update the cost for this node @@ -66,9 +70,9 @@ while (node !== null) { // Mark the node as processed processed = processed.concat(node); - + // Find the next node to process, and loop - node = find_lowest_cost_node(costs); + node = findLowestCostNode(costs); } console.log("Cost from the start to each node:"); diff --git a/09_dijkstras_algorithm/julia/01_dijkstras_algorithm.jl b/09_dijkstras_algorithm/julia/01_dijkstras_algorithm.jl new file mode 100644 index 00000000..3949267d --- /dev/null +++ b/09_dijkstras_algorithm/julia/01_dijkstras_algorithm.jl @@ -0,0 +1,64 @@ +# Julia version: LTS (v1.0.3) +using Test + +graph = Dict() +graph["start"] = Dict() +graph["start"]["a"] = 6 +graph["start"]["b"] = 2 + +graph["a"] = Dict() +graph["a"]["fin"] = 1 + +graph["b"] = Dict() +graph["b"]["a"] = 3 +graph["b"]["fin"] = 5 + +graph["fin"] = Dict() + +# the costs table +infinity = Inf +costs = Dict() +costs["a"] = 6 +costs["b"] = 2 +costs["fin"] = infinity + +# the parents table +parents = Dict() +parents["a"] = "start" +parents["b"] = "start" +parents["fin"] = nothing + +processed = [] + +function find_lowest_cost_node(costs) + lowest_cost = Inf + lowest_cost_node = nothing + for node in keys(costs) + cost = costs[node] + if cost < lowest_cost && node ∉ processed + lowest_cost = cost + lowest_cost_node = node + end + end + return lowest_cost_node +end + +node = find_lowest_cost_node(costs) +while node != nothing + global node + cost = costs[node] + neighbors = graph[node] + for n in keys(neighbors) + new_cost = cost + neighbors[n] + if costs[n] > new_cost + costs[n] = new_cost + parents[n] = node + end + end + push!(processed,node) + node = find_lowest_cost_node(costs) +end + +println("Cost from the start to each node:") +println(costs) +@test costs == Dict("fin"=>6,"b"=>2,"a"=>5) diff --git a/09_dijkstras_algorithm/kotlin/DijkstraAlgorithm.kt b/09_dijkstras_algorithm/kotlin/DijkstraAlgorithm.kt new file mode 100644 index 00000000..b17fde03 --- /dev/null +++ b/09_dijkstras_algorithm/kotlin/DijkstraAlgorithm.kt @@ -0,0 +1,77 @@ +// Граф +private val graph: MutableMap> = HashMap() + +// Список отслеживания обработанных узлов +private val processed: MutableList = ArrayList() + +fun main() { + graph["start"] = HashMap() + graph["start"]!!["a"] = 6.0 + graph["start"]!!["b"] = 2.0 + graph["a"] = HashMap() + graph["a"]!!["fin"] = 1.0 + graph["b"] = HashMap() + graph["b"]!!["a"] = 3.0 + graph["b"]!!["fin"] = 5.0 + graph["fin"] = HashMap() + + // Стоимость узлов + val costs: MutableMap = HashMap() + costs["a"] = 6.0 + costs["b"] = 2.0 + costs["fin"] = Double.POSITIVE_INFINITY + + // Таблица родителей + val parents: MutableMap = HashMap() + parents["a"] = "start" + parents["b"] = "start" + parents["fin"] = null + + + println("Cost from the start to each node:") + println(dijkstraAlgorithm(costs, parents)) +} + +fun dijkstraAlgorithm(costs: MutableMap, + parents: MutableMap): MutableMap { + + var node = findLowestCostNode(costs) + while (node != null) { + val cost = costs[node] + // Перебрать всех соседей текущего узла + val neighbors: Map = graph[node]!! + for (n in neighbors.keys) { + val newCost = cost!! + neighbors[n]!! + // Если к соседу можно быстрее добраться через текущий узел... + if (costs[n]!! > newCost) { + // ... обновить стоимость для этого узла + costs[n] = newCost + // Этот узел становится новым родителем для соседа + parents[n] = node + } + } + // Узел помечается как обработанный + processed.add(node) + + // Найти следующий узел для обработки и повторить цикл + node = findLowestCostNode(costs) + } + return costs // { a: 5, b: 2, fin: 6 } +} + +private fun findLowestCostNode(costs: Map): String? { + var lowestCost = Double.POSITIVE_INFINITY + var lowestCostNode: String? = null + + // Перебрать все узлы + for ((key, cost) in costs) { + // Если это узел с наименьшей стоимостью из уже виденных и + // он еще не был обработан... + if (cost < lowestCost && !processed.contains(key)) { + // ... он назначается новым узлом с наименьшей стоимостью + lowestCost = cost + lowestCostNode = key + } + } + return lowestCostNode +} \ No newline at end of file diff --git a/07_dijkstras_algorithm/lua/01_dijkstras_algorithm.lua b/09_dijkstras_algorithm/lua/01_dijkstras_algorithm.lua similarity index 100% rename from 07_dijkstras_algorithm/lua/01_dijkstras_algorithm.lua rename to 09_dijkstras_algorithm/lua/01_dijkstras_algorithm.lua diff --git a/07_dijkstras_algorithm/php/01_dijkstras_algorithm.php b/09_dijkstras_algorithm/php/01_dijkstras_algorithm.php similarity index 100% rename from 07_dijkstras_algorithm/php/01_dijkstras_algorithm.php rename to 09_dijkstras_algorithm/php/01_dijkstras_algorithm.php diff --git a/07_dijkstras_algorithm/python/01_dijkstras_algorithm.py b/09_dijkstras_algorithm/python/01_dijkstras_algorithm.py similarity index 100% rename from 07_dijkstras_algorithm/python/01_dijkstras_algorithm.py rename to 09_dijkstras_algorithm/python/01_dijkstras_algorithm.py diff --git a/07_dijkstras_algorithm/ruby/01_dijkstras_algorithm.rb b/09_dijkstras_algorithm/ruby/01_dijkstras_algorithm.rb similarity index 100% rename from 07_dijkstras_algorithm/ruby/01_dijkstras_algorithm.rb rename to 09_dijkstras_algorithm/ruby/01_dijkstras_algorithm.rb diff --git a/09_dijkstras_algorithm/rust/Cargo.lock b/09_dijkstras_algorithm/rust/Cargo.lock new file mode 100644 index 00000000..8ba83558 --- /dev/null +++ b/09_dijkstras_algorithm/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "dijkstra" +version = "0.1.0" diff --git a/09_dijkstras_algorithm/rust/Cargo.toml b/09_dijkstras_algorithm/rust/Cargo.toml new file mode 100644 index 00000000..e23f0cba --- /dev/null +++ b/09_dijkstras_algorithm/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "dijkstra" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/09_dijkstras_algorithm/rust/src/main.rs b/09_dijkstras_algorithm/rust/src/main.rs new file mode 100644 index 00000000..80e593ca --- /dev/null +++ b/09_dijkstras_algorithm/rust/src/main.rs @@ -0,0 +1,70 @@ +use std::{collections::HashMap, u64}; + +fn find_lowest_cost_node(processed: &Vec, costs: &HashMap) -> Option { + let mut lowest_cost = u64::MAX; + let mut lowest_cost_node = None; + for (node, cost) in costs.iter() { + if *cost < lowest_cost && !processed.contains(node) { + lowest_cost = *cost; + lowest_cost_node = Some(node); + } + } + return lowest_cost_node.cloned(); +} + +fn main() { + // Graph Setup + let mut graph = HashMap::new(); + + let mut start_edges: HashMap = HashMap::new(); + start_edges.insert("a".to_string(), 6); + start_edges.insert("b".to_string(), 2); + graph.insert("start".to_string(), start_edges); + + let mut a_edges = HashMap::new(); + a_edges.insert("fin".to_string(), 1); + graph.insert("a".to_string(), a_edges); + + let mut b_edges = HashMap::new(); + b_edges.insert("a".to_string(), 3); + b_edges.insert("fin".to_string(), 5); + graph.insert("b".to_string(), b_edges); + + let fin_edges = HashMap::new(); + graph.insert("fin".to_string(), fin_edges); + + // Costs Setup + let mut costs: HashMap = HashMap::new(); + costs.insert("a".to_string(), 6); + costs.insert("b".to_string(), 2); + costs.insert("fin".to_string(), u64::MAX); + + // Parents Setup + let mut parents = HashMap::new(); + parents.insert("a".to_string(), Some("start".to_string())); + parents.insert("b".to_string(), Some("start".to_string())); + parents.insert("fin".to_string(), None); + + let mut processed: Vec = vec![]; + + loop { + let node = find_lowest_cost_node(&processed, &costs); + match node { + Some(node) => { + let cost = *costs.get(&node).unwrap(); + let neighbors = graph.get(&node).unwrap(); + for (n, ncost) in neighbors.iter() { + let new_cost = cost + *ncost; + if *costs.get(n).unwrap() > new_cost { + costs.insert(n.to_string(), new_cost); + parents.insert(n.to_string(), Some(node.clone())); + } + } + processed.push(node) + } + None => break, + } + } + println!("costs: {:?}", costs); + println!("parents: {:?}", parents); +} diff --git a/07_dijkstras_algorithm/swift/01_dijkstras_algorithm.swift b/09_dijkstras_algorithm/swift/01_dijkstras_algorithm.swift similarity index 100% rename from 07_dijkstras_algorithm/swift/01_dijkstras_algorithm.swift rename to 09_dijkstras_algorithm/swift/01_dijkstras_algorithm.swift diff --git a/09_dijkstras_algorithm/ts/dijkstras_algorithm.ts b/09_dijkstras_algorithm/ts/dijkstras_algorithm.ts new file mode 100644 index 00000000..67ed3189 --- /dev/null +++ b/09_dijkstras_algorithm/ts/dijkstras_algorithm.ts @@ -0,0 +1,59 @@ +import { Graph, GraphIterable } from "./iterable_graph"; + +const dijkstraGraph: Graph> = { + start: { a: 6, b: 2 }, + a: { fin: 1 }, + b: { a: 3, fin: 5 }, + fin: {}, +}; + +const costs: Graph = { + a: 6, + b: 2, + fin: Infinity, +}; + +const parents: Graph = { + a: "start", + b: "start", + fin: null, +}; + +let processed: string[] = []; + +const findLowestCostNode = (costs: Graph): string | null => { + let lowestCost = Infinity; + let lowestCostNode: string | null = null; + + const iterableGraph = new GraphIterable(costs); + + for (const node of iterableGraph) { + const cost = costs[node]; + if (cost < lowestCost && !processed.includes(node)) { + lowestCost = cost; + lowestCostNode = node; + } + } + return lowestCostNode; +}; + +let node = findLowestCostNode(costs); + +while (node !== null) { + const cost = costs[node]; + + const neighbors = dijkstraGraph[node]; + Object.keys(neighbors).forEach((n: string) => { + const newCost = cost + neighbors[n]; + if (costs[n] > newCost) { + costs[n] = newCost; + parents[n] = node; + } + }); + + processed.push(node); + node = findLowestCostNode(costs); +} + +console.log("Cost from the start to each node:"); +console.log(costs); // { a: 5, b: 2, fin: 6 } diff --git a/09_dijkstras_algorithm/ts/iterable_graph.ts b/09_dijkstras_algorithm/ts/iterable_graph.ts new file mode 100644 index 00000000..7ba10b4b --- /dev/null +++ b/09_dijkstras_algorithm/ts/iterable_graph.ts @@ -0,0 +1,26 @@ +export interface Graph { + [key: string]: T; +} + +export class GraphIterable implements Iterable { + private graph: Graph; + + constructor(graph: Graph) { + this.graph = graph; + } + + [Symbol.iterator](): Iterator { + const keys = Object.keys(this.graph); + let index = 0; + + return { + next: (): IteratorResult => { + if (index < keys.length) { + return { value: keys[index++], done: false }; + } else { + return { value: undefined, done: true }; + } + }, + }; + } +} diff --git a/09_dijkstras_algorithm/zig/dijkstras_algorithm.zig b/09_dijkstras_algorithm/zig/dijkstras_algorithm.zig new file mode 100644 index 00000000..62fe9471 --- /dev/null +++ b/09_dijkstras_algorithm/zig/dijkstras_algorithm.zig @@ -0,0 +1,157 @@ +const std = @import("std"); +const mem = std.mem; +const heap = std.heap; + +pub fn main() !void { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + var arena = heap.ArenaAllocator.init(gpa.allocator()); + defer arena.deinit(); + const alloc = arena.allocator(); + + var graph = std.StringHashMap(*std.StringHashMap(f32)).init(alloc); + + var start = std.StringHashMap(f32).init(alloc); + try start.put("a", 6); + try start.put("b", 2); + try start.put("c", 42); + try graph.put("start", &start); + + var a = std.StringHashMap(f32).init(alloc); + try a.put("finish", 1); + try graph.put("a", &a); + + var b = std.StringHashMap(f32).init(alloc); + try b.put("a", 3); + try b.put("finish", 5); + try graph.put("b", &b); + + var c = std.StringHashMap(f32).init(alloc); + try c.put("finish", 42); + try graph.put("c", &c); + + var fin = std.StringHashMap(f32).init(alloc); + try graph.put("finish", &fin); + + var costs, var path = try dijkstra(alloc, &graph, "start", "finish"); + + // Traverse the path hashmap backwards from finish to start and store the + // steps in an ordered list. + // The hashmap is unordered so there is no guarantee to print the path in + // the correct order only by iterating through key/value(s). + var dir = std.ArrayList([]const u8).init(alloc); + + var v: []const u8 = "finish"; + try dir.append(v); + var node = path.get(v); + while (node) |n| : (node = path.get(v)) { + try dir.append(n.?); + v = n.?; + } + std.debug.print("Path from start to finish:\n", .{}); + std.debug.print("start =(", .{}); + var i = dir.items.len - 2; + var prev_cost: f32 = 0; + while (i > 0) : (i -= 1) { + const d = dir.items[i]; + const cost = costs.get(d).?; + std.debug.print("{d})=> {s:<6}: {d}\n{s:<5} =(", .{ cost - prev_cost, d, cost, d }); + prev_cost = cost; + } + const fin_cost = costs.get("finish").?; + std.debug.print("{d})=> finish: {d}\n", .{ fin_cost - prev_cost, fin_cost }); +} + +/// applies the dijkstra algorithm on graph using start and finish nodes. +/// Returns a tuple with the costs and the path. +fn dijkstra( + allocator: mem.Allocator, + graph: *std.StringHashMap(*std.StringHashMap(f32)), + start: []const u8, + finish: []const u8, +) !struct { + std.StringHashMap(f32), // costs + std.StringHashMap(?[]const u8), // path +} { + var costs = std.StringHashMap(f32).init(allocator); + var parents = std.StringHashMap(?[]const u8).init(allocator); + try costs.put(finish, std.math.inf(f32)); + try parents.put(finish, null); + + // initialize costs and parents maps for the nodes having start as parent + const start_graph = graph.get(start) orelse return error.MissingNode; + var sg_it = start_graph.iterator(); + while (sg_it.next()) |elem| { + try parents.put(elem.key_ptr.*, start); + try costs.put(elem.key_ptr.*, elem.value_ptr.*); + } + + var processed = std.BufSet.init(allocator); + + var n = findCheapestNode(&costs, &processed); + while (n) |node| : (n = findCheapestNode(&costs, &processed)) { + const cost = costs.get(node).?; + const neighbors = graph.get(node) orelse return error.MissingNode; + var it = neighbors.iterator(); + while (it.next()) |neighbor| { + const new_cost = cost + neighbor.value_ptr.*; + if (costs.get(neighbor.key_ptr.*).? > new_cost) { + // update maps if we found a cheaper path + try costs.put(neighbor.key_ptr.*, new_cost); + try parents.put(neighbor.key_ptr.*, node); + } + } + try processed.insert(node); + } + + return .{ costs, parents }; +} + +/// finds the cheapest node among the not yet processed ones. +fn findCheapestNode(costs: *std.StringHashMap(f32), processed: *std.BufSet) ?[]const u8 { + var lowest_cost = std.math.inf(f32); + var lowest_cost_node: ?[]const u8 = null; + + var it = costs.iterator(); + while (it.next()) |node| { + if (node.value_ptr.* < lowest_cost and !processed.contains(node.key_ptr.*)) { + lowest_cost = node.value_ptr.*; + lowest_cost_node = node.key_ptr.*; + } + } + + return lowest_cost_node; +} + +test "dijkstra" { + var arena = heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const alloc = arena.allocator(); + + var graph = std.StringHashMap(*std.StringHashMap(f32)).init(alloc); + + var start = std.StringHashMap(f32).init(alloc); + try start.put("a", 6); + try start.put("b", 2); + try graph.put("start", &start); + + var a = std.StringHashMap(f32).init(alloc); + try a.put("finish", 1); + try graph.put("a", &a); + + var b = std.StringHashMap(f32).init(alloc); + try b.put("a", 3); + try b.put("finish", 5); + try graph.put("b", &b); + + var fin = std.StringHashMap(f32).init(alloc); + try graph.put("finish", &fin); + + var costs, var path = try dijkstra(alloc, &graph, "start", "finish"); + + try std.testing.expectEqual(costs.get("a").?, 5); + try std.testing.expectEqual(costs.get("b").?, 2); + try std.testing.expectEqual(costs.get("finish").?, 6); + try std.testing.expectEqual(path.get("b").?, "start"); + try std.testing.expectEqual(path.get("a").?, "b"); + try std.testing.expectEqual(path.get("finish").?, "a"); +} diff --git a/09_dynamic_programming/ES6/01_longest_common_subsequence.js b/09_dynamic_programming/ES6/01_longest_common_subsequence.js deleted file mode 100644 index 366d23e9..00000000 --- a/09_dynamic_programming/ES6/01_longest_common_subsequence.js +++ /dev/null @@ -1,54 +0,0 @@ -function createMatrix(rows, cols) { - const matrix = new Array(rows); - - for (let i = 0; i < matrix.length; i++) { - matrix[i] = new Array(cols).fill(0); - } - - return matrix; -} - -function substring(a, b) { - const cell = createMatrix(a.length + 1, b.length + 1); - let lcs = 0; - let lastSubIndex = 0; - - for (let i = 1; i <= a.length; i++) { - for (let j = 1; j <= b.length; j++) { - if (a[i - 1] === b[j - 1]) { - cell[i][j] = cell[i - 1][j - 1] + 1; - - if (cell[i][j] > lcs) { - lcs = cell[i][j]; - lastSubIndex = i; - } - } else { - cell[i][j] = 0; - } - } - } - - return a.slice(lastSubIndex - lcs, lastSubIndex); -} - -substring("vista", "hish"); // "is" -substring("fish", "hish"); // "ish" - -function subsequence(a, b) { - const cell = createMatrix(a.length + 1, b.length + 1); - - for (let i = 1; i <= a.length; i++) { - for (let j = 1; j <= b.length; j++) { - if (a[i] === b[j]) { - cell[i][j] = cell[i - 1][j - 1] + 1; - } else { - cell[i][j] = Math.max(cell[i - 1][j], cell[i][j - 1]); - } - } - } - - return cell[a.length][b.length]; -} - -subsequence("fish", "fosh"); // 3 -subsequence("fort", "fosh"); // 2 diff --git a/09_dynamic_programming/ES6/examples/base.js b/09_dynamic_programming/ES6/examples/base.js deleted file mode 100644 index d50dda8e..00000000 --- a/09_dynamic_programming/ES6/examples/base.js +++ /dev/null @@ -1,7 +0,0 @@ -export const initializeMatrix = (rows, cols) => { - const matrix = []; - for (let i = 0; i < rows.length; i += 1) { - matrix.push(Array(cols.length).fill(0)); - } - return matrix; -}; diff --git a/09_dynamic_programming/ES6/examples/diff_two_words.js b/09_dynamic_programming/ES6/examples/diff_two_words.js deleted file mode 100644 index 1ac7d02c..00000000 --- a/09_dynamic_programming/ES6/examples/diff_two_words.js +++ /dev/null @@ -1,27 +0,0 @@ -import { initializeMatrix } from "./base"; - -const diff = (firstWord, secondWord) => { - const arr1 = firstWord.split(""); - const arr2 = secondWord.split(""); - const matrix = initializeMatrix(arr1, arr2); - for (let i = 0; i < arr1.length; i += 1) { - for (let j = 0; j < arr2.length; j += 1) { - if (arr1[i] === arr2[j]) { - if (i > 0 && j > 0) { - matrix[i][j] = matrix[i - 1][j - 1] + 1; - } else { - matrix[i][j] = 1; - } - } else { - if (i > 0 && j > 0) { - matrix[i][j] = Math.max(matrix[i - 1][j], matrix[i][j - 1]); - } else { - matrix[i][j] = 0; - } - } - } - } - return matrix[arr1.length - 1][arr2.length - 1]; -}; - -export default diff; diff --git a/09_dynamic_programming/csharp/01_longest_common_subsequence/.vscode/launch.json b/09_dynamic_programming/csharp/01_longest_common_subsequence/.vscode/launch.json deleted file mode 100644 index 5706467a..00000000 --- a/09_dynamic_programming/csharp/01_longest_common_subsequence/.vscode/launch.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": ".NET Core Launch (console)", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - "program": "${workspaceRoot}/bin/Debug/netcoreapp1.0/01_longest_common_subsequence.dll", - "args": [], - "cwd": "${workspaceRoot}", - "externalConsole": false, - "stopAtEntry": false, - "internalConsoleOptions": "openOnSessionStart" - }, - { - "name": ".NET Core Attach", - "type": "coreclr", - "request": "attach", - "processId": "${command.pickProcess}" - } - ] -} \ No newline at end of file diff --git a/09_dynamic_programming/csharp/01_longest_common_subsequence/.vscode/tasks.json b/09_dynamic_programming/csharp/01_longest_common_subsequence/.vscode/tasks.json deleted file mode 100644 index adc66239..00000000 --- a/09_dynamic_programming/csharp/01_longest_common_subsequence/.vscode/tasks.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "version": "0.1.0", - "command": "dotnet", - "isShellCommand": true, - "args": [], - "tasks": [ - { - "taskName": "build", - "args": [ - "${workspaceRoot}/project.json" - ], - "isBuildCommand": true, - "problemMatcher": "$msCompile" - } - ] -} \ No newline at end of file diff --git a/09_dynamic_programming/csharp/01_longest_common_subsequence/Program.cs b/09_dynamic_programming/csharp/01_longest_common_subsequence/Program.cs deleted file mode 100644 index 63ebdbae..00000000 --- a/09_dynamic_programming/csharp/01_longest_common_subsequence/Program.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace ConsoleApplication -{ - public class Program - { - public static void Main(string[] args) - { - - if (word_a[i] == word_b[1]) - { - cell[i][j] = cell[i - 1][j - 1] + 1; - } - else - { - cell[i][j] = Math.Max(cell[i - 1][j], cell[i][j - 1]); - } - } - } -} diff --git a/09_dynamic_programming/elixir/01_longest_common_subsequence.exs b/09_dynamic_programming/elixir/01_longest_common_subsequence.exs deleted file mode 100644 index c9bcb66f..00000000 --- a/09_dynamic_programming/elixir/01_longest_common_subsequence.exs +++ /dev/null @@ -1,12 +0,0 @@ -# `cell` is a map of maps here, e.g. -# cell = %{ -# 0 => %{0 => 0, ...}, -# 1 => %{...}, -# ... -# } - -if String.at(word_a, i) == String.at(word_a, j) do - put_in(cell[i - 1][j - 1], cell[i - 1][j - 1] + 1) -else - put_in(cell[i - 1][j - 1], max(cell[i - 1][j], cell[i][j - 1])) -end diff --git a/09_dynamic_programming/python/01_longest_common_subsequence.py b/09_dynamic_programming/python/01_longest_common_subsequence.py deleted file mode 100644 index 9f74f936..00000000 --- a/09_dynamic_programming/python/01_longest_common_subsequence.py +++ /dev/null @@ -1,6 +0,0 @@ -if word_a[i] == word_b[j]: - # The letters match. - cell[i][j] = cell[i-1][j-1] + 1 -else: - # The letters don't match. - cell[i][j] = max(cell[i-1][j], cell[i][j-1]) diff --git a/08_greedy_algorithms/ES6/01_set_covering.js b/10_greedy_algorithms/ES6/01_set_covering.js similarity index 64% rename from 08_greedy_algorithms/ES6/01_set_covering.js rename to 10_greedy_algorithms/ES6/01_set_covering.js index 2e075ccf..8f934155 100644 --- a/08_greedy_algorithms/ES6/01_set_covering.js +++ b/10_greedy_algorithms/ES6/01_set_covering.js @@ -1,20 +1,19 @@ // You pass an array in, and it gets converted to a set. -let statesNeeded = new Set(['mt', 'wa', 'or', 'id', 'nv', 'ut', 'ca', 'az']); +let statesNeeded = new Set(["mt", "wa", "or", "id", "nv", "ut", "ca", "az"]); const stations = {}; -stations.kone = new Set(['id', 'nv', 'ut']); -stations.ktwo = new Set(['wa', 'id', 'mt']); -stations.kthree = new Set(['or', 'nv', 'ca']); -stations.kfour = new Set(['nv', 'ut']); -stations.kfive = new Set(['ca', 'az']); +stations.kone = new Set(["id", "nv", "ut"]); +stations.ktwo = new Set(["wa", "id", "mt"]); +stations.kthree = new Set(["or", "nv", "ca"]); +stations.kfour = new Set(["nv", "ut"]); +stations.kfive = new Set(["ca", "az"]); const finalStations = new Set(); - while (statesNeeded.size) { let bestStation = null; let statesCovered = new Set(); - Object.keys(stations).forEach((station) => { + Object.keys(stations).forEach(station => { const states = stations[station]; const covered = new Set([...statesNeeded].filter(x => states.has(x))); if (covered.size > statesCovered.size) { diff --git a/08_greedy_algorithms/Haskell/01_powerset-covering.hs b/10_greedy_algorithms/Haskell/01_powerset-covering.hs similarity index 100% rename from 08_greedy_algorithms/Haskell/01_powerset-covering.hs rename to 10_greedy_algorithms/Haskell/01_powerset-covering.hs diff --git a/08_greedy_algorithms/Haskell/01_set_convering.hs b/10_greedy_algorithms/Haskell/01_set_convering.hs similarity index 100% rename from 08_greedy_algorithms/Haskell/01_set_convering.hs rename to 10_greedy_algorithms/Haskell/01_set_convering.hs diff --git a/08_greedy_algorithms/PowerShell/01_set_covering.ps1 b/10_greedy_algorithms/PowerShell/01_set_covering.ps1 similarity index 100% rename from 08_greedy_algorithms/PowerShell/01_set_covering.ps1 rename to 10_greedy_algorithms/PowerShell/01_set_covering.ps1 diff --git a/10_greedy_algorithms/c++11/01_set_covering.cpp b/10_greedy_algorithms/c++11/01_set_covering.cpp new file mode 100644 index 00000000..b5b6125b --- /dev/null +++ b/10_greedy_algorithms/c++11/01_set_covering.cpp @@ -0,0 +1,59 @@ +#include +#include +#include + +std::unordered_set operator & (const std::unordered_set&, + const std::unordered_set&); +void operator -= (std::unordered_set&, + const std::unordered_set&); + +int main() { + std::unordered_set statesNeeded({ "mt", "wa", "or", "id", "nv", "ut", "ca", "az" }); + + std::unordered_map> stations; + stations.insert({ "kone", {"id", "nv", "ut"} }); + stations.insert({ "ktwo", {"wa", "id", "mt" } }); + stations.insert({ "kthree", {"or", "nv", "ca" } }); + stations.insert({ "kfour", {"nv", "ut" } }); + stations.insert({ "kfive", {"ca", "az" } }); + + std::unordered_set finalStations; + + while (!statesNeeded.empty()) { + std::string bestStation; + std::unordered_set statesCovered; + for (const auto& i : stations) { + std::unordered_set coverage = i.second & statesNeeded; + if (coverage.size() > statesCovered.size()) { + bestStation = i.first; + statesCovered = coverage; + } + } + statesNeeded -= statesCovered; + finalStations.insert(bestStation); + } + + for (const auto& i : finalStations) + std::cout << i << std::endl; + + system("pause"); + return 0; +} + + std::unordered_set operator & (const std::unordered_set& a, + const std::unordered_set& b) { + std::unordered_set result; + for (const auto& i : a) + for (const auto& j : b) + if (i == j) + result.insert(i); + return result; + } + +void operator -= (std::unordered_set& a, + const std::unordered_set& b) { + for (auto j = b.begin(); j != b.end(); ++j) + for (auto i = a.begin(); i != a.end(); ) + if (*i == *j) i = a.erase(i); + else ++i; + } diff --git a/08_greedy_algorithms/csharp/01_set_covering/.gitignore b/10_greedy_algorithms/csharp/01_set_covering/.gitignore similarity index 100% rename from 08_greedy_algorithms/csharp/01_set_covering/.gitignore rename to 10_greedy_algorithms/csharp/01_set_covering/.gitignore diff --git a/08_greedy_algorithms/csharp/01_set_covering/Program.cs b/10_greedy_algorithms/csharp/01_set_covering/Program.cs similarity index 100% rename from 08_greedy_algorithms/csharp/01_set_covering/Program.cs rename to 10_greedy_algorithms/csharp/01_set_covering/Program.cs diff --git a/08_greedy_algorithms/csharp/01_set_covering/project.json b/10_greedy_algorithms/csharp/01_set_covering/project.json similarity index 100% rename from 08_greedy_algorithms/csharp/01_set_covering/project.json rename to 10_greedy_algorithms/csharp/01_set_covering/project.json diff --git a/08_greedy_algorithms/csharp/01_set_covering/project.lock.json b/10_greedy_algorithms/csharp/01_set_covering/project.lock.json similarity index 100% rename from 08_greedy_algorithms/csharp/01_set_covering/project.lock.json rename to 10_greedy_algorithms/csharp/01_set_covering/project.lock.json diff --git a/10_greedy_algorithms/d/01_set_covering.d b/10_greedy_algorithms/d/01_set_covering.d new file mode 100644 index 00000000..837233a1 --- /dev/null +++ b/10_greedy_algorithms/d/01_set_covering.d @@ -0,0 +1,40 @@ +module app; + +import std; + +alias Set = bool[string]; + +void main() +{ + Set statesNeeded = assocArray(["mt", "wa", "or", "id", "nv", "ut", "ca", "az"], true.repeat); + Set[string] stations; + stations["kone"] = assocArray(["id", "nv", "ut"], true.repeat); + stations["ktwo"] = assocArray(["wa", "id", "mt"], true.repeat); + stations["kthree"] = assocArray(["or", "nv", "ca"], true.repeat); + stations["kfour"] = assocArray(["nv", "ut"], true.repeat); + stations["kfive"] = assocArray(["ca", "az"], true.repeat); + + Set finalStations; + + while (!statesNeeded.empty) + { + string bestStation; + Set statesCovered; + foreach(station; stations.byPair) + { + auto coverage = setIntersection(station.value.keys.sort, statesNeeded.keys.sort).array; + if (coverage.length > statesCovered.keys.length) + { + bestStation = station.key; + statesCovered = assocArray(coverage, true.repeat); + } + } + if (statesCovered.length) + { + foreach(st; statesCovered.keys) + statesNeeded.remove(st); + } + finalStations[bestStation] = true; + } + writeln(finalStations.keys); +} diff --git a/10_greedy_algorithms/dart/01_set_covering.dart b/10_greedy_algorithms/dart/01_set_covering.dart new file mode 100644 index 00000000..de3a9644 --- /dev/null +++ b/10_greedy_algorithms/dart/01_set_covering.dart @@ -0,0 +1,52 @@ +void main(List args) { + final fruits = {'avocado', 'tomato', 'banana'}; + final vegetables = {'beet', 'carrot', 'tomato'}; + + print(fruits.union(vegetables)); + print(fruits.intersection(vegetables)); + print(fruits.difference(vegetables)); + print(vegetables.difference(fruits)); + + final coverStates = { + 'mt', + 'wa', + 'or', + 'id', + 'nv', + 'ut', + 'ca', + 'az', + }; + + final stations = >{}..addAll( + { + 'kone': {'id', 'nv', 'uy'}, + 'ktwo': {'wa', 'id', 'mt'}, + 'kthree': {'or', 'nv', 'ca'}, + 'kfour': {'nv', 'ut'}, + 'kfive': {'ca', 'az'}, + }, + ); + + final finalStations = stationSet(coverStates, stations); + print(finalStations); +} + +Set stationSet( + Set coverStates, Map> stations) { + final finalStations = {}; + while (coverStates.isNotEmpty) { + String? bestStation; + Set coveredStates = {}; + for (String station in stations.keys) { + final covered = coverStates.intersection(stations[station] ?? {}); + if (covered.length > coveredStates.length) { + bestStation = station; + coveredStates = covered; + } + } + coverStates.removeWhere((element) => coveredStates.contains(element)); + finalStations.add(bestStation!); + } + return finalStations; +} diff --git a/08_greedy_algorithms/elixir/01_set_covering.exs b/10_greedy_algorithms/elixir/01_set_covering.exs similarity index 100% rename from 08_greedy_algorithms/elixir/01_set_covering.exs rename to 10_greedy_algorithms/elixir/01_set_covering.exs diff --git a/08_greedy_algorithms/golang/01_set_covering.go b/10_greedy_algorithms/golang/01_set_covering.go similarity index 100% rename from 08_greedy_algorithms/golang/01_set_covering.go rename to 10_greedy_algorithms/golang/01_set_covering.go diff --git a/08_greedy_algorithms/java/01_set_covering/src/SetCovering.java b/10_greedy_algorithms/java/01_set_covering/src/SetCovering.java similarity index 56% rename from 08_greedy_algorithms/java/01_set_covering/src/SetCovering.java rename to 10_greedy_algorithms/java/01_set_covering/src/SetCovering.java index 86f07910..c9cbff64 100644 --- a/08_greedy_algorithms/java/01_set_covering/src/SetCovering.java +++ b/10_greedy_algorithms/java/01_set_covering/src/SetCovering.java @@ -1,10 +1,9 @@ import java.util.*; public class SetCovering { - - public static void main(String[] args) { - Set statesNeeded = new HashSet(Arrays.asList("mt", "wa", "or", "id", "nv", "ut", "ca", "az")); - Map> stations = new LinkedHashMap<>(); + public static void main(String... args) { + var statesNeeded = new HashSet<>(Arrays.asList("mt", "wa", "or", "id", "nv", "ut", "ca", "az")); + var stations = new LinkedHashMap>(); stations.put("kone", new HashSet<>(Arrays.asList("id", "nv", "ut"))); stations.put("ktwo", new HashSet<>(Arrays.asList("wa", "id", "mt"))); @@ -12,26 +11,26 @@ public static void main(String[] args) { stations.put("kfour", new HashSet<>(Arrays.asList("nv", "ut"))); stations.put("kfive", new HashSet<>(Arrays.asList("ca", "az"))); - Set finalStations = new HashSet(); + var finalStations = new HashSet(); while (!statesNeeded.isEmpty()) { String bestStation = null; - Set statesCovered = new HashSet<>(); + var statesCovered = new HashSet(); - for (Map.Entry> station : stations.entrySet()) { - Set covered = new HashSet<>(statesNeeded); + for (var station : stations.entrySet()) { + var covered = new HashSet<>(statesNeeded); covered.retainAll(station.getValue()); if (covered.size() > statesCovered.size()) { bestStation = station.getKey(); statesCovered = covered; } - statesNeeded.removeIf(statesCovered::contains); + } + statesNeeded.removeIf(statesCovered::contains); - if (bestStation != null) { - finalStations.add(bestStation); - } + if (bestStation != null) { + finalStations.add(bestStation); } } System.out.println(finalStations); // [ktwo, kone, kthree, kfive] } -} \ No newline at end of file +} diff --git a/10_greedy_algorithms/javascript/01_set_covering.js b/10_greedy_algorithms/javascript/01_set_covering.js new file mode 100644 index 00000000..5b49f955 --- /dev/null +++ b/10_greedy_algorithms/javascript/01_set_covering.js @@ -0,0 +1,30 @@ +"use strict"; + +// You pass an array in, and it gets converted to a set. +let statesNeeded = new Set(["mt", "wa", "or", "id", "nv", "ut", "ca", "az"]); + +const stations = {}; +stations["kone"] = new Set(["id", "nv", "ut"]); +stations["ktwo"] = new Set(["wa", "id", "mt"]); +stations["kthree"] = new Set(["or", "nv", "ca"]); +stations["kfour"] = new Set(["nv", "ut"]); +stations["kfive"] = new Set(["ca", "az"]); + +const finalStations = new Set(); + +while (statesNeeded.size) { + let bestStation = null; + let statesCovered = new Set(); + for (let station in stations) { + const states = stations[station]; + const covered = new Set([...statesNeeded].filter(x => states.has(x))); + if (covered.size > statesCovered.size) { + bestStation = station; + statesCovered = covered; + } + } + statesNeeded = new Set([...statesNeeded].filter(x => !statesCovered.has(x))); + finalStations.add(bestStation); +} + +console.log(finalStations); // Set { 'kone', 'ktwo', 'kthree', 'kfive' } diff --git a/10_greedy_algorithms/kotlin/01_set_covering.kt b/10_greedy_algorithms/kotlin/01_set_covering.kt new file mode 100644 index 00000000..5049fee5 --- /dev/null +++ b/10_greedy_algorithms/kotlin/01_set_covering.kt @@ -0,0 +1,26 @@ +var statesNeeded = setOf("mt", "wa", "or", "id", "nv", "ut", "ca", "az") +val stations = mapOf( + "kone" to setOf("id", "nv", "ut"), + "ktwo" to setOf("wa", "id", "mt"), + "kthree" to setOf("or", "nv", "ca"), + "kfour" to setOf("nv", "ut"), + "kfive" to setOf("ca", "az") +) + +fun main() { + val finalStations = mutableSetOf() + while (statesNeeded.isNotEmpty()) { + var bestStation: String? = null + var statesCovered = setOf() + stations.forEach { (station, states) -> + val covered = statesNeeded.intersect(states) + if (covered.size > statesCovered.size) { + bestStation = station + statesCovered = covered + } + } + statesNeeded = statesNeeded - statesCovered + bestStation?.let { finalStations.add(it) } + } + println(finalStations) +} \ No newline at end of file diff --git a/08_greedy_algorithms/lua/01_set_covering.lua b/10_greedy_algorithms/lua/01_set_covering.lua similarity index 100% rename from 08_greedy_algorithms/lua/01_set_covering.lua rename to 10_greedy_algorithms/lua/01_set_covering.lua diff --git a/08_greedy_algorithms/lua/set.lua b/10_greedy_algorithms/lua/set.lua similarity index 100% rename from 08_greedy_algorithms/lua/set.lua rename to 10_greedy_algorithms/lua/set.lua diff --git a/08_greedy_algorithms/php/01_set_covering.php b/10_greedy_algorithms/php/01_set_covering.php similarity index 100% rename from 08_greedy_algorithms/php/01_set_covering.php rename to 10_greedy_algorithms/php/01_set_covering.php diff --git a/10_greedy_algorithms/python/01_set_covering.py b/10_greedy_algorithms/python/01_set_covering.py new file mode 100644 index 00000000..6e2f9f77 --- /dev/null +++ b/10_greedy_algorithms/python/01_set_covering.py @@ -0,0 +1,30 @@ +# You pass an array in, and it gets converted to a set. +states_needed = set(["mt", "wa", "or", "id", "nv", "ut", "ca", "az"]) + +stations = {} +stations["kone"] = set(["id", "nv", "ut"]) +stations["ktwo"] = set(["wa", "id", "mt"]) +stations["kthree"] = set(["or", "nv", "ca"]) +stations["kfour"] = set(["nv", "ut"]) +stations["kfive"] = set(["ca", "az"]) + + +def my_set_covering(states_needed, stations): + final_stations = set() + while states_needed: + best_station = None + states_covered = set() + for station, states_for_station in stations.items(): + covered = states_needed & states_for_station + if len(covered) > len(states_covered) and station not in final_stations: + best_station = station + states_covered = covered + if best_station is not None: + states_needed -= states_covered + final_stations.add(best_station) + stations.pop(best_station) + else: + return None + return final_stations + +print(my_set_covering(states_needed, stations)) diff --git a/08_greedy_algorithms/ruby/01_set_covering.rb b/10_greedy_algorithms/ruby/01_set_covering.rb similarity index 100% rename from 08_greedy_algorithms/ruby/01_set_covering.rb rename to 10_greedy_algorithms/ruby/01_set_covering.rb diff --git a/10_greedy_algorithms/rust/Cargo.lock b/10_greedy_algorithms/rust/Cargo.lock new file mode 100644 index 00000000..957b7a80 --- /dev/null +++ b/10_greedy_algorithms/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "greedy_algorithms" +version = "0.1.0" diff --git a/10_greedy_algorithms/rust/Cargo.toml b/10_greedy_algorithms/rust/Cargo.toml new file mode 100644 index 00000000..c4e8ff31 --- /dev/null +++ b/10_greedy_algorithms/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "greedy_algorithms" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/10_greedy_algorithms/rust/src/main.rs b/10_greedy_algorithms/rust/src/main.rs new file mode 100644 index 00000000..220df521 --- /dev/null +++ b/10_greedy_algorithms/rust/src/main.rs @@ -0,0 +1,42 @@ +use std::collections::{HashMap, HashSet}; + +fn main() { + let mut states_needed = HashSet::from(["mt", "wa", "or", "id", "nv", "ut", "ca", "az"]); + + let mut stations = HashMap::from([ + ("kone", HashSet::from(["id", "nv", "ut"])), + ("ktwo", HashSet::from(["wa", "id", "mt"])), + ("kthree", HashSet::from(["or", "nv", "ca"])), + ("kfour", HashSet::from(["nv", "ut"])), + ("kfive", HashSet::from(["ca", "az"])), + ]); + + let mut final_stations = HashSet::new(); + while !states_needed.is_empty() { + let mut best_station = None; + let mut states_covered = HashSet::new(); + for (station, states_for_station) in &stations { + let covered: HashSet<_> = states_needed + .intersection(&states_for_station) + .cloned() + .collect(); + if covered.len() > states_covered.len() && !final_stations.contains(station) { + best_station = Some(*station); + states_covered = covered; + } + } + match best_station { + Some(station) => { + states_needed = states_needed.difference(&states_covered).cloned().collect(); + final_stations.insert(station); + stations.remove(station); + } + None => { + println!("Coold not complete: {:?}", final_stations); + break; + } + } + } + + println!("{:?}", final_stations); +} diff --git a/08_greedy_algorithms/swift/01_set_covering.swift b/10_greedy_algorithms/swift/01_set_covering.swift similarity index 100% rename from 08_greedy_algorithms/swift/01_set_covering.swift rename to 10_greedy_algorithms/swift/01_set_covering.swift diff --git a/10_greedy_algorithms/ts/01_set_covering.ts b/10_greedy_algorithms/ts/01_set_covering.ts new file mode 100644 index 00000000..eb2e7415 --- /dev/null +++ b/10_greedy_algorithms/ts/01_set_covering.ts @@ -0,0 +1,34 @@ +// You pass an array in, and it gets converted to a set. +let statesNeeded: Set = new Set(["mt", "wa", "or", "id", "nv", "ut", "ca", "az"]); + +const stations: Record> = {}; +stations["kone"] = new Set(["id", "nv", "ut"]); +stations["ktwo"] = new Set(["wa", "id", "mt"]); +stations["kthree"] = new Set(["or", "nv", "ca"]); +stations["kfour"] = new Set(["nv", "ut"]); +stations["kfive"] = new Set(["ca", "az"]); + +const finalStations: Set = new Set(); + +while (statesNeeded.size) { + let bestStation: string | null = null; + let statesCovered: Set = new Set(); + + for (let station in stations) { + const states = stations[station]; + const covered = new Set([...statesNeeded].filter(x => states.has(x))); + + if (covered.size > statesCovered.size) { + bestStation = station; + statesCovered = covered; + } + } + + statesNeeded = new Set([...statesNeeded].filter(x => !statesCovered.has(x))); + + if (bestStation !== null) { + finalStations.add(bestStation); + } +} + +console.log(finalStations); // Set { 'kone', 'ktwo', 'kthree', 'kfive' } \ No newline at end of file diff --git a/10_greedy_algorithms/ts/tsconfig.json b/10_greedy_algorithms/ts/tsconfig.json new file mode 100644 index 00000000..d4027c48 --- /dev/null +++ b/10_greedy_algorithms/ts/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "lib": [ + "dom", + "es2015", + "es2016", + "es2017" + ], + "target": "es2015" + } + } + \ No newline at end of file diff --git a/10_greedy_algorithms/zig/set_covering.zig b/10_greedy_algorithms/zig/set_covering.zig new file mode 100644 index 00000000..e8431bf5 --- /dev/null +++ b/10_greedy_algorithms/zig/set_covering.zig @@ -0,0 +1,256 @@ +const std = @import("std"); +const heap = std.heap; +const mem = std.mem; + +pub fn main() !void { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + var arena = heap.ArenaAllocator.init(gpa.allocator()); + defer arena.deinit(); + + const ally = arena.allocator(); + const states_needed_array = [_][]const u8{ "mt", "wa", "or", "id", "nv", "ut", "ca", "az" }; + var states_needed = std.BufSet.init(ally); + for (states_needed_array) |sn| { + try states_needed.insert(sn); + } + + var stations = std.StringHashMap(*std.BufSet).init(ally); + + var k_one = std.BufSet.init(ally); + try k_one.insert("id"); + try k_one.insert("nv"); + try k_one.insert("ut"); + + var k_two = std.BufSet.init(ally); + try k_two.insert("wa"); + try k_two.insert("id"); + try k_two.insert("mt"); + + var k_three = std.BufSet.init(ally); + try k_three.insert("or"); + try k_three.insert("nv"); + try k_three.insert("ca"); + + var k_four = std.BufSet.init(ally); + try k_four.insert("nv"); + try k_four.insert("ut"); + + var k_five = std.BufSet.init(ally); + try k_five.insert("ca"); + try k_five.insert("az"); + + try stations.put("kone", &k_one); + try stations.put("ktwo", &k_two); + try stations.put("kthree", &k_three); + try stations.put("kfour", &k_four); + try stations.put("kfive", &k_five); + + const stations_covering = try setCovering(ally, &stations, &states_needed); + + for (stations_covering) |sc| { + std.debug.print("{s}\n", .{sc}); + } +} + +fn setCovering(allocator: mem.Allocator, stations: *std.StringHashMap(*std.BufSet), states_needed: *std.BufSet) ![][]const u8 { + var final_stations = std.BufSet.init(allocator); + + while (states_needed.count() > 0) { + var best_station: []const u8 = undefined; + var states_covered: [][]const u8 = &[_][]const u8{}; + + var it = stations.iterator(); + while (it.next()) |station| { + var covered = std.ArrayList([]const u8).init(allocator); + try intersect(states_needed, station.value_ptr.*, &covered); + if (covered.items.len > states_covered.len) { + best_station = station.key_ptr.*; + states_covered = covered.items; + } else covered.deinit(); + } + + difference(states_needed, states_covered); + try final_stations.insert(best_station); + } + + var final_array = std.ArrayList([]const u8).init(allocator); + var i = final_stations.iterator(); + while (i.next()) |key| { + try final_array.append(key.*); + } + + return final_array.toOwnedSlice(); +} + +test "setCovering" { + var arena = heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const ally = arena.allocator(); + + const states_needed_array = [_][]const u8{ "mt", "wa", "or", "id", "nv", "ut", "ca", "az" }; + var states_needed = std.BufSet.init(ally); + for (states_needed_array) |sn| { + try states_needed.insert(sn); + } + + var stations = std.StringHashMap(*std.BufSet).init(ally); + + var kone = std.BufSet.init(ally); + try kone.insert("id"); + try kone.insert("nv"); + try kone.insert("ut"); + try stations.put("kone", &kone); + + var ktwo = std.BufSet.init(ally); + try ktwo.insert("wa"); + try ktwo.insert("id"); + try ktwo.insert("mt"); + try stations.put("ktwo", &ktwo); + + var kthree = std.BufSet.init(ally); + try kthree.insert("or"); + try kthree.insert("nv"); + try kthree.insert("ca"); + try stations.put("kthree", &kthree); + + var kfour = std.BufSet.init(ally); + try kfour.insert("nv"); + try kfour.insert("ut"); + try stations.put("kfour", &kfour); + + var kfive = std.BufSet.init(ally); + try kfive.insert("ca"); + try kfive.insert("az"); + try stations.put("kfive", &kfive); + + const stations_covering = try setCovering(ally, &stations, &states_needed); + + // The order of the keys in the hashmap affects the final result. + // StringHashMap always produces the same order and we can assert over it. + const expectedStations = &[_][]const u8{ "kfour", "ktwo", "kthree", "kfive" }; + for (stations_covering, 0..) |sc, i| { + try std.testing.expectEqualStrings(expectedStations[i], sc); + } +} + +fn intersect(left: *std.BufSet, right: *std.BufSet, intersection: *std.ArrayList([]const u8)) !void { + var l_it = left.iterator(); + while (l_it.next()) |l| { + var r_it = right.iterator(); + while (r_it.next()) |r| { + if (std.mem.eql(u8, l.*, r.*)) { + try intersection.append(l.*); + } + } + } +} + +test "intersect" { + var arena = heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const ally = arena.allocator(); + + var left = std.BufSet.init(ally); + try left.insert("banana"); + try left.insert("mango"); + try left.insert("papaya"); + + var right = std.BufSet.init(ally); + try right.insert("banana"); + try right.insert("mango"); + try right.insert("avocado"); + + { + // partial intersection + const expected = &[2][]const u8{ "banana", "mango" }; + var actual = std.ArrayList([]const u8).init(ally); + + try intersect(&left, &right, &actual); + + for (actual.items, expected) |a, e| { + try std.testing.expectEqualStrings(e, a); + } + } + { + // full intersection + const expected = &[3][]const u8{ "banana", "mango", "papaya" }; + var actual = std.ArrayList([]const u8).init(ally); + + try intersect(&left, &left, &actual); + + for (actual.items, expected) |a, e| { + try std.testing.expectEqualStrings(e, a); + } + } + { + // no intersection + var empty = std.BufSet.init(ally); + var actual = std.ArrayList([]const u8).init(ally); + + try intersect(&left, &empty, &actual); + + try std.testing.expect(actual.items.len == 0); + } +} + +fn difference(lessening: *std.BufSet, subtracting: [][]const u8) void { + var less_it = lessening.iterator(); + + while (less_it.next()) |less| { + for (subtracting) |sub| { + if (std.mem.eql(u8, less.*, sub)) { + lessening.remove(less.*); + } + } + } +} + +test "difference" { + var arena = heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const ally = arena.allocator(); + + { + // partial diff + var less = std.BufSet.init(ally); + try less.insert("banana"); + try less.insert("mango"); + try less.insert("papaya"); + + var sub = [_][]const u8{ "banana", "mango" }; + + difference(&less, &sub); + + try std.testing.expect(less.count() == 1); + try std.testing.expect(less.contains("papaya")); + } + { + // full diff + var less = std.BufSet.init(ally); + try less.insert("banana"); + try less.insert("mango"); + try less.insert("papaya"); + + var sub = [_][]const u8{ "avocado", "kiwi", "ananas" }; + + difference(&less, &sub); + + try std.testing.expect(less.count() == 3); + try std.testing.expect(less.contains("banana")); + try std.testing.expect(less.contains("mango")); + try std.testing.expect(less.contains("papaya")); + } + { + // no diff + var less = std.BufSet.init(ally); + try less.insert("banana"); + try less.insert("mango"); + try less.insert("papaya"); + + var sub = [_][]const u8{ "mango", "papaya", "banana" }; + + difference(&less, &sub); + + try std.testing.expect(less.count() == 0); + } +} diff --git a/11_dynamic_programming/ES6/01_longest_common_subsequence.js b/11_dynamic_programming/ES6/01_longest_common_subsequence.js new file mode 100644 index 00000000..f23a7cf2 --- /dev/null +++ b/11_dynamic_programming/ES6/01_longest_common_subsequence.js @@ -0,0 +1,78 @@ +/** + * Create a matrix + * @param {number} rows Number of rows + * @param {number} columns ANumber of columns + * @returns {Array} Matrix + */ +const createMatrix = (rows = 0, columns = 0) => { + const matrix = []; + + for (let i = 0; i < rows; i++) { + matrix[i] = Array(columns).fill(0); + } + + return matrix; +}; + +/** + * Find the longest substring + * @param {string} firstWord First word + * @param {string} secondWord Second word + * @returns {string} The longest substring + */ +const longestSubstring = (firstWord = "", secondWord = "") => { + const matrix = JSON.parse( + JSON.stringify(createMatrix(firstWord.length, secondWord.length)) + ); + let sizeSequence = 0; + let indexSequence = 0; + + for (let i = 0; i < firstWord.length; i++) { + for (let j = 0; j < secondWord.length; j++) { + if (firstWord[i] === secondWord[j]) { + matrix[i][j] = (i && j) > 0 ? matrix[i - 1][j - 1] + 1 : 1; + + if (matrix[i][j] >= sizeSequence) { + sizeSequence = matrix[i][j]; + indexSequence = i + 1; + } + } else { + matrix[i][j] = 0; + } + } + } + + return firstWord.slice(indexSequence - sizeSequence, indexSequence); +}; + +longestSubstring("vista", "hish"); // "is" +longestSubstring("fish", "hish"); // "ish" + +/** + * Find the longest common subsequence + * @param {string} firstWord First word + * @param {string} secondWord Second word + * @returns {number} The longest common subsequence + */ +const longestCommonSubsequence = (firstWord = "", secondWord = "") => { + const matrix = JSON.parse( + JSON.stringify(createMatrix(firstWord.length, secondWord.length)) + ); + if (matrix.length === 0 || matrix[0].length === 0) return 0; + for (let i = 0; i < firstWord.length; i++) { + for (let j = 0; j < secondWord.length; j++) { + if (firstWord[i] === secondWord[j]) { + matrix[i][j] = (i && j) > 0 ? matrix[i - 1][j - 1] + 1 : 1; + } else { + matrix[i][j] = Math.max( + i > 0 ? matrix[i - 1][j] : 0, + j > 0 ? matrix[i][j - 1] : 0 + ); + } + } + } + return matrix[firstWord.length - 1][secondWord.length - 1]; +}; + +longestCommonSubsequence("fish", "fosh"); // 3 +longestCommonSubsequence("fort", "fosh"); // 2 diff --git a/09_dynamic_programming/Haskell/01_knapsack-powerset.hs b/11_dynamic_programming/Haskell/01_knapsack-powerset.hs similarity index 100% rename from 09_dynamic_programming/Haskell/01_knapsack-powerset.hs rename to 11_dynamic_programming/Haskell/01_knapsack-powerset.hs diff --git a/09_dynamic_programming/Haskell/01_knapsack_dynamic_prog.hs b/11_dynamic_programming/Haskell/01_knapsack_dynamic_prog.hs similarity index 100% rename from 09_dynamic_programming/Haskell/01_knapsack_dynamic_prog.hs rename to 11_dynamic_programming/Haskell/01_knapsack_dynamic_prog.hs diff --git a/09_dynamic_programming/PowerShell/01_longest_common_subsequence.ps1 b/11_dynamic_programming/PowerShell/01_longest_common_subsequence.ps1 similarity index 100% rename from 09_dynamic_programming/PowerShell/01_longest_common_subsequence.ps1 rename to 11_dynamic_programming/PowerShell/01_longest_common_subsequence.ps1 diff --git a/09_dynamic_programming/csharp/01_longest_common_subsequence/.gitignore b/11_dynamic_programming/csharp/01_longest_common_subsequence/.gitignore similarity index 100% rename from 09_dynamic_programming/csharp/01_longest_common_subsequence/.gitignore rename to 11_dynamic_programming/csharp/01_longest_common_subsequence/.gitignore diff --git a/11_dynamic_programming/csharp/01_longest_common_subsequence/Program.cs b/11_dynamic_programming/csharp/01_longest_common_subsequence/Program.cs new file mode 100644 index 00000000..83f10d49 --- /dev/null +++ b/11_dynamic_programming/csharp/01_longest_common_subsequence/Program.cs @@ -0,0 +1,72 @@ +using System; + +namespace ConsoleApplication +{ + public class Program + { + public static void Main(string[] args) + { + var result = LongestCommonSubsequence("fish", "vistafh"); + Console.WriteLine($"{result.Item1}: {result.Item2}"); // ish: 3 + } + + public static (string, int) LongestCommonSubsequence(string word1, string word2) + { + if (string.IsNullOrEmpty(word1) || string.IsNullOrEmpty(word2)) + return ("", 0); + + string subSeq; + var matrix = new int[word1.Length + 1, word2.Length + 1]; + + for (int i = 1; i <= word1.Length; i++) + { + for (int j = 1; j <= word2.Length; j++) + { + if (word1[i - 1] == word2[j - 1]) + { + matrix[i, j] = matrix[i - 1, j - 1] + 1; + } + else + { + matrix[i, j] = Math.Max(matrix[i, j - 1], matrix[i - 1, j]); + } + } + } + + subSeq = Read(matrix, word1, word2); + + return (subSeq, subSeq.Length); + } + + private static string Read(int[,] matrix, string word1, string word2) + { + string subSeq = null; + int x = word1.Length; + int y = word2.Length; + + while (x > 0 && y > 0) + { + if (word1[x - 1] == word2[y - 1]) + { + subSeq += word1[x - 1]; + x--; + y--; + } + else if (matrix[x - 1, y] > matrix[x, y - 1]) + { + x--; + } + else + { + y--; + } + } + + var charArray = subSeq.ToCharArray(); + Array.Reverse(charArray); + subSeq = new string(charArray); + + return subSeq; + } + } +} diff --git a/09_dynamic_programming/csharp/01_longest_common_subsequence/project.json b/11_dynamic_programming/csharp/01_longest_common_subsequence/project.json similarity index 100% rename from 09_dynamic_programming/csharp/01_longest_common_subsequence/project.json rename to 11_dynamic_programming/csharp/01_longest_common_subsequence/project.json diff --git a/09_dynamic_programming/csharp/01_longest_common_subsequence/project.lock.json b/11_dynamic_programming/csharp/01_longest_common_subsequence/project.lock.json similarity index 100% rename from 09_dynamic_programming/csharp/01_longest_common_subsequence/project.lock.json rename to 11_dynamic_programming/csharp/01_longest_common_subsequence/project.lock.json diff --git a/11_dynamic_programming/csharp/02_levenshtein/Program.cs b/11_dynamic_programming/csharp/02_levenshtein/Program.cs new file mode 100644 index 00000000..29704c63 --- /dev/null +++ b/11_dynamic_programming/csharp/02_levenshtein/Program.cs @@ -0,0 +1,46 @@ +using System; + +namespace ConsoleApplication +{ + public class Program + { + public static int LevenshteinDistance(string source, string target) + { + var matrix = CreateMatrix(source, target); + + for (int i = 1; i <= source.Length; i++) + { + for (int j = 1; j <= target.Length; j++) + { + matrix[i, j] = Math.Min(matrix[i, j - 1] + 1, Math.Min( + matrix[i - 1, j] + 1, + matrix[i - 1, j - 1] + (source[i - 1] != target[j - 1] ? 1 : 0))); + } + } + + return matrix[source.Length, target.Length]; + } + + private static int[,] CreateMatrix(string source, string target) + { + var matrix = new int[source.Length + 1, target.Length + 1]; + + if (source.Length < target.Length) + { + (source, target) = (target, source); + } + + for (int i = 0; i <= source.Length; i++) + { + matrix[i, 0] = i; + + if (i <= target.Length) + { + matrix[0, i] = i; + } + } + + return matrix; + } + } +} diff --git a/11_dynamic_programming/d/01_longest_common_sub.d b/11_dynamic_programming/d/01_longest_common_sub.d new file mode 100644 index 00000000..35f9aa36 --- /dev/null +++ b/11_dynamic_programming/d/01_longest_common_sub.d @@ -0,0 +1,53 @@ +module app; + +import std; + +alias DpTable = ulong[][]; + +DpTable longest_common_substring(T)(T[] table1, T[] table2) +{ + DpTable dp_table = new DpTable(table1.length, table2.length); + + foreach(i, c1; table1) + foreach(j, c2; table2) + { + if (c1 == c2) + dp_table[i][j] = dp_table[i > 0 ? i - 1 : 0][j > 0 ? j - 1 : 0] + 1; + else + dp_table[i][j] = 0; + } + return dp_table; +} + + +DpTable longest_common_subsequence(T)(T[] table1, T[] table2) +{ + DpTable dp_table = new DpTable(table1.length, table2.length); + + foreach(i, c1; table1) + foreach(j, c2; table2) + { + if (c1 == c2) + dp_table[i][j] = dp_table[i > 0 ? i-1 : 0][j > 0 ? j-1 : 0] + 1; + else + { + dp_table[i][j] = max(dp_table[i > 0 ? i-1 : 0][j], + dp_table[i][j > 0 ? j-1 : 0]); + } + } + return dp_table; +} + +void main() +{ + auto dp_table_blue = "blue"; + auto dp_table_clues = "clues"; + + writeln("Longest substring:"); + foreach(line; longest_common_substring(dp_table_blue.array, dp_table_clues.array)) + writeln(line); + + writeln("Longest subsequence:"); + foreach(line; longest_common_subsequence(dp_table_blue.array, dp_table_clues.array)) + writeln(line); +} diff --git a/11_dynamic_programming/dart/01_longest_common_subsequence.dart b/11_dynamic_programming/dart/01_longest_common_subsequence.dart new file mode 100644 index 00000000..ae621ab0 --- /dev/null +++ b/11_dynamic_programming/dart/01_longest_common_subsequence.dart @@ -0,0 +1,27 @@ +void main(List args) { + final table = longestCommonSubsequence('blue', 'clues'); + + for (List element in table) { + print(element); + } +} + +List> longestCommonSubsequence(String word1, String word2) { + final tableWord1 = word1.split(''); + final tableWord2 = word2.split(''); + final table = List.generate( + tableWord2.length, (index) => List.filled(tableWord1.length, 0)); + + for (int i = 0; i < tableWord1.length; i++) { + for (int j = 0; j < tableWord2.length; j++) { + if (tableWord2[j] == tableWord1[i]) { + table[j][i] = (j - 1 >= 0 && i - 1 >= 0) ? table[j - 1][i - 1] + 1 : 1; + } else { + final top = (j - 1 >= 0) ? table[j - 1][i] : 0; + final left = (i - 1 >= 0) ? table[j][i - 1] : 0; + table[j][i] = (top > left) ? top : left; + } + } + } + return table; +} diff --git a/11_dynamic_programming/dart/02_longest_common_substring.dart b/11_dynamic_programming/dart/02_longest_common_substring.dart new file mode 100644 index 00000000..7a7d9582 --- /dev/null +++ b/11_dynamic_programming/dart/02_longest_common_substring.dart @@ -0,0 +1,25 @@ +void main(List args) { + final table = longestCommonSubstring('fish', 'hish'); + + for (List element in table) { + print(element); + } +} + +List> longestCommonSubstring(String word1, String word2) { + final tableWord1 = word1.split(''); + final tableWord2 = word2.split(''); + final table = List.generate( + tableWord2.length, (index) => List.filled(tableWord1.length, 0)); + + for (int i = 0; i < tableWord1.length; i++) { + for (int j = 0; j < tableWord2.length; j++) { + if (tableWord2[j] == tableWord1[i]) { + table[j][i] = table[j - 1][j - 1] + 1; + } else { + table[j][i] = 0; + } + } + } + return table; +} diff --git a/11_dynamic_programming/elixir/01_longest_common_subsequence.exs b/11_dynamic_programming/elixir/01_longest_common_subsequence.exs new file mode 100644 index 00000000..1cfe0c5d --- /dev/null +++ b/11_dynamic_programming/elixir/01_longest_common_subsequence.exs @@ -0,0 +1,51 @@ +defmodule LCSubsequence do + def generate_table(word_a, word_b) do + word_a + |> Enum.with_index() + |> Enum.reduce(%{}, fn {_x, index}, acc -> + nested_map = + word_b + |> Enum.with_index() + |> Enum.reduce(%{}, fn {_x, index}, acc -> + Map.put(acc, index, 0) + end) + + Map.put(acc, index, nested_map) + end) + end + + def compute(table, word_a, word_b) do + for i <- 0..(length(word_a) - 1), reduce: table do + table -> + for j <- 0..(length(word_b) - 1), reduce: table do + table -> + if Enum.at(word_a, i) == Enum.at(word_b, j) do + value = (table[i - 1][j - 1] || 0) + 1 + put_in(table[i][j], value) + else + first = table[i - 1][j] || 0 + second = table[i][j - 1] || 0 + put_in(table[i][j], max(first, second)) + end + end + end + end +end + +word_a = ["b", "l", "u", "e"] +word_b = ["c", "l", "u", "e", "s"] + +result = + word_a + |> LCSubsequence.generate_table(word_b) + |> LCSubsequence.compute(word_a, word_b) + +Enum.each(result, fn {_index, value} -> + IO.inspect(Map.values(value)) +end) + +# Output +# [0, 0, 0, 0, 0] +# [0, 1, 1, 1, 1] +# [0, 1, 2, 2, 2] +# [0, 1, 2, 3, 3] diff --git a/11_dynamic_programming/elixir/02_longest_common_substring.exs b/11_dynamic_programming/elixir/02_longest_common_substring.exs new file mode 100644 index 00000000..ddbaad94 --- /dev/null +++ b/11_dynamic_programming/elixir/02_longest_common_substring.exs @@ -0,0 +1,49 @@ +defmodule LCSubstring do + def generate_table(word_a, word_b) do + word_a + |> Enum.with_index() + |> Enum.reduce(%{}, fn {_x, index}, acc -> + nested_map = + word_b + |> Enum.with_index() + |> Enum.reduce(%{}, fn {_x, index}, acc -> + Map.put(acc, index, 0) + end) + + Map.put(acc, index, nested_map) + end) + end + + def compute(table, word_a, word_b) do + for i <- 0..(length(word_a) - 1), reduce: table do + table -> + for j <- 0..(length(word_b) - 1), reduce: table do + table -> + if Enum.at(word_a, i) == Enum.at(word_b, j) do + value = (table[i - 1][j - 1] || 0) + 1 + put_in(table[i][j], value) + else + put_in(table[i][j], 0) + end + end + end + end +end + +word_a = ["b", "l", "u", "e"] +word_b = ["c", "l", "u", "e", "s"] + +result = + word_a + |> LCSubstring.generate_table(word_b) + |> LCSubstring.compute(word_a, word_b) + +Enum.each(result, fn {_index, value} -> + IO.inspect(Map.values(value)) +end) + +# Output +# [0, 0, 0, 0, 0] +# [0, 1, 0, 0, 0] +# [0, 0, 2, 0, 0] +# [0, 0, 0, 3, 0] diff --git a/09_dynamic_programming/golang/01_longest_common_subsequence.go b/11_dynamic_programming/golang/01_longest_common_subsequence.go similarity index 100% rename from 09_dynamic_programming/golang/01_longest_common_subsequence.go rename to 11_dynamic_programming/golang/01_longest_common_subsequence.go diff --git a/09_dynamic_programming/golang/01_longest_common_subsequence_test.go b/11_dynamic_programming/golang/01_longest_common_subsequence_test.go similarity index 100% rename from 09_dynamic_programming/golang/01_longest_common_subsequence_test.go rename to 11_dynamic_programming/golang/01_longest_common_subsequence_test.go diff --git a/09_dynamic_programming/java/01_longest_common_subsequence/src/LongestCommonSubsequence.java b/11_dynamic_programming/java/01_longest_common_subsequence/src/LongestCommonSubsequence.java similarity index 100% rename from 09_dynamic_programming/java/01_longest_common_subsequence/src/LongestCommonSubsequence.java rename to 11_dynamic_programming/java/01_longest_common_subsequence/src/LongestCommonSubsequence.java diff --git a/09_dynamic_programming/javascript/01_longest_common_subsequence.js b/11_dynamic_programming/javascript/01_longest_common_subsequence.js similarity index 100% rename from 09_dynamic_programming/javascript/01_longest_common_subsequence.js rename to 11_dynamic_programming/javascript/01_longest_common_subsequence.js diff --git a/09_dynamic_programming/javascript/02_levenstein.js b/11_dynamic_programming/javascript/02_levenstein.js similarity index 100% rename from 09_dynamic_programming/javascript/02_levenstein.js rename to 11_dynamic_programming/javascript/02_levenstein.js diff --git a/09_dynamic_programming/javascript/examples/base.js b/11_dynamic_programming/javascript/examples/base.js similarity index 100% rename from 09_dynamic_programming/javascript/examples/base.js rename to 11_dynamic_programming/javascript/examples/base.js diff --git a/09_dynamic_programming/javascript/examples/diff_two_words.js b/11_dynamic_programming/javascript/examples/diff_two_words.js similarity index 100% rename from 09_dynamic_programming/javascript/examples/diff_two_words.js rename to 11_dynamic_programming/javascript/examples/diff_two_words.js diff --git a/11_dynamic_programming/kotlin/LongestCommonSubsequence.kt b/11_dynamic_programming/kotlin/LongestCommonSubsequence.kt new file mode 100644 index 00000000..8e22281e --- /dev/null +++ b/11_dynamic_programming/kotlin/LongestCommonSubsequence.kt @@ -0,0 +1,37 @@ +import kotlin.math.max + +fun main() { + val wordA = "hish" + val wordB = "fish" + getLongestCommonSubSequence(wordA, wordB) +} + +private fun getLongestCommonSubSequence(wordA: String, wordB: String) { + val cell = Array(wordA.length) { IntArray(wordB.length) } + for (i in wordA.indices) { + for (j in wordB.indices) { + // Буквы совпадают + if (wordA[i] == wordB[j]) { + if (i > 0 && j > 0) { + cell[i][j] = cell[i - 1][j - 1] + 1 + } else { + cell[i][j] = 1 + } + } else { + // Буквы не совпадают + if (i > 0 && j > 0) { + cell[i][j] = max(cell[i - 1][j], cell[i][j - 1]) + } else { + cell[i][j] = 0 + } + } + } + } + printResult(cell) +} + +fun printResult(array: Array) { + for (row in array) { + println(row.contentToString()) + } +} diff --git a/09_dynamic_programming/lua/01_longest_common_subsequence.lua b/11_dynamic_programming/lua/01_longest_common_subsequence.lua similarity index 100% rename from 09_dynamic_programming/lua/01_longest_common_subsequence.lua rename to 11_dynamic_programming/lua/01_longest_common_subsequence.lua diff --git a/09_dynamic_programming/php/01_longest_common_subsequence.php b/11_dynamic_programming/php/01_longest_common_subsequence.php similarity index 100% rename from 09_dynamic_programming/php/01_longest_common_subsequence.php rename to 11_dynamic_programming/php/01_longest_common_subsequence.php diff --git a/11_dynamic_programming/python/01_longest_common_subsequence.py b/11_dynamic_programming/python/01_longest_common_subsequence.py new file mode 100644 index 00000000..315b2336 --- /dev/null +++ b/11_dynamic_programming/python/01_longest_common_subsequence.py @@ -0,0 +1,15 @@ +dp_table_blue = ["b", "l", "u", "e"] +dp_table_clues = ["c", "l", "u", "e", "s"] +dp_table = [[0 for i in range(len(dp_table_clues))] for i in range(len(dp_table_blue))] # (5,4) + +# for each row +for i in range(0, len(dp_table_blue)): + # for each column + for j in range(0, len(dp_table_clues)): + if dp_table_clues[j] == dp_table_blue[i]: + dp_table[i][j] = dp_table[i-1][j-1] + 1 + else: + dp_table[i][j] = max(dp_table[i-1][j], dp_table[i][j-1]) + +for i in dp_table: + print(i) diff --git a/11_dynamic_programming/python/02_longest_common_substring.py b/11_dynamic_programming/python/02_longest_common_substring.py new file mode 100644 index 00000000..1e879a58 --- /dev/null +++ b/11_dynamic_programming/python/02_longest_common_substring.py @@ -0,0 +1,16 @@ +dp_table_blue = ["b", "l", "u", "e"] +dp_table_clues = ["c", "l", "u", "e", "s"] +dp_table = [[0 for i in range(len(dp_table_clues))] for i in range(len(dp_table_blue))] # (5,4) + +# for each row +for i in range(0, len(dp_table_blue)): + # for each col + for j in range(0, len(dp_table_clues)): + if dp_table_clues[j] == dp_table_blue[i]: + dp_table[i][j] = dp_table[i-1][j-1] + 1 + else: + dp_table[i][j] = 0 + +# display table +for i in dp_table: + print(i) diff --git a/09_dynamic_programming/ruby/01_longest_common_subsequence.rb b/11_dynamic_programming/ruby/01_longest_common_subsequence.rb similarity index 100% rename from 09_dynamic_programming/ruby/01_longest_common_subsequence.rb rename to 11_dynamic_programming/ruby/01_longest_common_subsequence.rb diff --git a/11_dynamic_programming/rust/Cargo.lock b/11_dynamic_programming/rust/Cargo.lock new file mode 100644 index 00000000..1cf52686 --- /dev/null +++ b/11_dynamic_programming/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "longest_common" +version = "0.1.0" diff --git a/11_dynamic_programming/rust/Cargo.toml b/11_dynamic_programming/rust/Cargo.toml new file mode 100644 index 00000000..91aa97f3 --- /dev/null +++ b/11_dynamic_programming/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "longest_common" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/11_dynamic_programming/rust/src/main.rs b/11_dynamic_programming/rust/src/main.rs new file mode 100644 index 00000000..dffbe91b --- /dev/null +++ b/11_dynamic_programming/rust/src/main.rs @@ -0,0 +1,65 @@ +use std::cmp; + +fn build_dp_table(table1: &[T], table2: &[T]) -> Vec> { + let mut dp_table = vec![]; + for i in 0..table1.len() { + dp_table.push(vec![]); + for _ in 0..table2.len() { + dp_table[i].push(0); + } + } + + dp_table +} + +fn longest_common_substring(table1: &[T], table2: &[T]) -> Vec> { + let mut dp_table = build_dp_table(table1, table2); + + for (i, c1) in table1.into_iter().enumerate() { + for (j, c2) in table2.into_iter().enumerate() { + if c1 == c2 { + dp_table[i][j] = + dp_table[i.checked_sub(1).unwrap_or(0)][j.checked_sub(1).unwrap_or(0)] + 1; + } else { + dp_table[i][j] = 0; + } + } + } + + dp_table +} + +fn longest_common_subsequence(table1: &[T], table2: &[T]) -> Vec> { + let mut dp_table = build_dp_table(table1, table2); + + for (i, c1) in table1.into_iter().enumerate() { + for (j, c2) in table2.into_iter().enumerate() { + if c1 == c2 { + dp_table[i][j] = + dp_table[i.checked_sub(1).unwrap_or(0)][j.checked_sub(1).unwrap_or(0)] + 1; + } else { + dp_table[i][j] = cmp::max( + dp_table[i.checked_sub(1).unwrap_or(0)][j], + dp_table[i][j.checked_sub(1).unwrap_or(0)], + ); + } + } + } + + dp_table +} + +fn main() { + let dp_table_blue = ['b', 'l', 'u', 'e']; + let dp_table_clues = ['c', 'l', 'u', 'e', 's']; + + println!("Longest substring:"); + for line in longest_common_substring(&dp_table_blue, &dp_table_clues) { + println!("{:?}", line) + } + + println!("Longest subsequence:"); + for line in longest_common_subsequence(&dp_table_blue, &dp_table_clues) { + println!("{:?}", line) + } +} diff --git a/09_dynamic_programming/swift/01_longest_common_subsequence.swift b/11_dynamic_programming/swift/01_longest_common_subsequence.swift similarity index 100% rename from 09_dynamic_programming/swift/01_longest_common_subsequence.swift rename to 11_dynamic_programming/swift/01_longest_common_subsequence.swift diff --git a/11_dynamic_programming/ts/01_longest_common_subsequence.ts b/11_dynamic_programming/ts/01_longest_common_subsequence.ts new file mode 100644 index 00000000..3483c090 --- /dev/null +++ b/11_dynamic_programming/ts/01_longest_common_subsequence.ts @@ -0,0 +1,69 @@ +/** + * Search for LCS + * + * @param {string} string1 first string + * @param {string} string2 second string + * + * @return {object} with keys: lcs, offset, sequence + */ +function lcs(string1: string, string2: string): { lcs: number; offset: number; sequence: string } { + if (typeof string1 !== "string" || typeof string2 !== "string" || !string1 || !string2) { + return { + lcs: 0, + offset: 0, + sequence: "" + }; + } + + let lcs = 0; + let lastSubIndex = 0; + + const table: number[][] = []; + const len1 = string1.length; + const len2 = string2.length; + + let row: number; + let col: number; + + for (row = 0; row <= len1; row++) { + table[row] = []; + for (col = 0; col <= len2; col++) { + table[row][col] = 0; + } + } + + let i: number; + let j: number; + + for (i = 0; i < len1; i++) { + for (j = 0; j < len2; j++) { + if (string1[i] === string2[j]) { + if (table[i][j] === 0) { + table[i + 1][j + 1] = 1; + } else { + table[i + 1][j + 1] = table[i][j] + 1; + } + + if (table[i + 1][j + 1] > lcs) { + lcs = table[i + 1][j + 1]; + lastSubIndex = i; + } + } else { + table[i + 1][j + 1] = 0; + } + } + } + + return { + lcs: lcs, + offset: lastSubIndex - lcs + 1, + sequence: string1.slice(lastSubIndex - lcs + 1, lastSubIndex + 1) + }; +} + +// Test cases +console.log(lcs("hish", "fish")); // { lcs: 3, offset: 1, sequence: 'ish' } +console.log(lcs("vista", "hish")); // { lcs: 2, offset: 1, sequence: 'is' } +console.log(lcs("google", "abcdefgooglehijklm")); // { lcs: 6, offset: 0, sequence: 'google' } +console.log(lcs("0", "0")); // { lcs: 1, offset: 0, sequence: '0' } +console.log(lcs("0", 0 as any)); // { lcs: 0, offset: 0, sequence: '' } \ No newline at end of file diff --git a/11_dynamic_programming/ts/tsconfig.json b/11_dynamic_programming/ts/tsconfig.json new file mode 100644 index 00000000..d4027c48 --- /dev/null +++ b/11_dynamic_programming/ts/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "lib": [ + "dom", + "es2015", + "es2016", + "es2017" + ], + "target": "es2015" + } + } + \ No newline at end of file diff --git a/11_dynamic_programming/zig/longest_common_subsequence.zig b/11_dynamic_programming/zig/longest_common_subsequence.zig new file mode 100644 index 00000000..8ad71000 --- /dev/null +++ b/11_dynamic_programming/zig/longest_common_subsequence.zig @@ -0,0 +1,63 @@ +const std = @import("std"); +const heap = std.heap; +const math = std.math; +const expect = std.testing.expect; +const expectEqualStrings = std.testing.expectEqualStrings; + +pub fn main() !void { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + var arena = heap.ArenaAllocator.init(gpa.allocator()); + defer arena.deinit(); + + const n, const sub = try subsequence(arena.allocator(), "fish", "fosh"); + std.debug.print("{d}: {s}\n", .{ n, sub }); +} + +fn subsequence(allocator: std.mem.Allocator, a: []const u8, b: []const u8) !struct { u32, []const u8 } { + var grid = try allocator.alloc([]u32, a.len + 1); + var subseq = try std.ArrayList(u8).initCapacity(allocator, @max(a.len, b.len)); + + for (grid) |*row| { + row.* = try allocator.alloc(u32, b.len + 1); + for (row.*) |*cell| { + cell.* = 0; + } + } + + var i: usize = 1; + while (i <= a.len) : (i += 1) { + var j: usize = 1; + while (j <= b.len) : (j += 1) { + if (a[i - 1] == b[j - 1]) { + grid[i][j] = grid[i - 1][j - 1] + 1; + try subseq.append(a[i - 1]); + } else { + grid[i][j] = @max(grid[i][j - 1], grid[i - 1][j]); + } + } + } + + const sub = try subseq.toOwnedSlice(); + return .{ grid[a.len][b.len], sub }; +} + +test "subsequence" { + const tests = [_]struct { + a: []const u8, + b: []const u8, + expected: struct { u32, []const u8 }, + }{ + .{ .a = "abc", .b = "abcd", .expected = .{ 3, "abc" } }, + .{ .a = "pera", .b = "mela", .expected = .{ 2, "ea" } }, + .{ .a = "banana", .b = "kiwi", .expected = .{ 0, "" } }, + }; + + for (tests) |t| { + var arena = heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + + const actual = try subsequence(arena.allocator(), t.a, t.b); + + try std.testing.expectEqualDeep(t.expected, actual); + } +} diff --git "a/11_dynamic_programming/\321\201++/01_longest_common_subsequence.cpp" "b/11_dynamic_programming/\321\201++/01_longest_common_subsequence.cpp" new file mode 100644 index 00000000..a0837120 --- /dev/null +++ "b/11_dynamic_programming/\321\201++/01_longest_common_subsequence.cpp" @@ -0,0 +1,43 @@ +#include +#include + +int main() { + std::string wordA = "Fish", wordB = "Fosh"; + const size_t& aSize = wordA.size(), &bSize = wordB.size(); + + size_t** table = new size_t* [aSize]; + for (size_t l = 0; l < aSize; ++l) + table[l] = new size_t[bSize]{}; // all values in table will be initialized as zero + + for (size_t i = 0; i < aSize; ++i) + for (size_t j = 0; j < bSize; ++j) + if (wordA[i] == wordB[j]) + if (i > 0 && j > 0) + table[i][j] = table[i - 1][j - 1] + 1; + else + table[i][j] = 1; + else + if (i > 0 && j > 0) + table[i][j] = std::max(table[i - 1][j], table[i][j - 1]); + else if (i == 0 && j > 0) + table[i][j] = table[i][j - 1]; + else if (i > 0 && j == 0) + table[i][j] = table[i - 1][j]; + else + table[i][j] = 0; + + for (size_t i = 0; i < aSize; ++i) { + std::cout << "[ "; + for (size_t j = 0; j < bSize; ++j) + std::cout << table[i][j] << ' '; + std::cout << ']' << std::endl; + } + + // [1 1 1 1] + // [1 1 1 1] + // [1 1 2 2] + // [1 1 2 3] + + system("pause"); + return 0; +} diff --git a/10_knn/README.md b/12_knn/README.md similarity index 100% rename from 10_knn/README.md rename to 12_knn/README.md diff --git a/10_knn/images/13_correct_50_comparisons.tif b/12_knn/images/13_correct_50_comparisons.tif similarity index 100% rename from 10_knn/images/13_correct_50_comparisons.tif rename to 12_knn/images/13_correct_50_comparisons.tif diff --git a/10_knn/images/16_correct_500_comparisons.tif b/12_knn/images/16_correct_500_comparisons.tif similarity index 100% rename from 10_knn/images/16_correct_500_comparisons.tif rename to 12_knn/images/16_correct_500_comparisons.tif diff --git a/10_knn/images/17_correct_500_comparisons.png b/12_knn/images/17_correct_500_comparisons.png similarity index 100% rename from 10_knn/images/17_correct_500_comparisons.png rename to 12_knn/images/17_correct_500_comparisons.png diff --git a/10_knn/images/18_correct_5000_comparisons.tif b/12_knn/images/18_correct_5000_comparisons.tif similarity index 100% rename from 10_knn/images/18_correct_5000_comparisons.tif rename to 12_knn/images/18_correct_5000_comparisons.tif diff --git a/10_knn/images/19_correct_50000_comparisons.tif b/12_knn/images/19_correct_50000_comparisons.tif similarity index 100% rename from 10_knn/images/19_correct_50000_comparisons.tif rename to 12_knn/images/19_correct_50000_comparisons.tif diff --git a/10_knn/main.m b/12_knn/main.m similarity index 100% rename from 10_knn/main.m rename to 12_knn/main.m diff --git a/10_knn/mnistHelper/loadMNISTImages.m b/12_knn/mnistHelper/loadMNISTImages.m similarity index 100% rename from 10_knn/mnistHelper/loadMNISTImages.m rename to 12_knn/mnistHelper/loadMNISTImages.m diff --git a/10_knn/mnistHelper/loadMNISTLabels.m b/12_knn/mnistHelper/loadMNISTLabels.m similarity index 100% rename from 10_knn/mnistHelper/loadMNISTLabels.m rename to 12_knn/mnistHelper/loadMNISTLabels.m diff --git a/10_knn/t10k-images-idx3-ubyte b/12_knn/t10k-images-idx3-ubyte similarity index 100% rename from 10_knn/t10k-images-idx3-ubyte rename to 12_knn/t10k-images-idx3-ubyte diff --git a/10_knn/t10k-labels-idx1-ubyte b/12_knn/t10k-labels-idx1-ubyte similarity index 100% rename from 10_knn/t10k-labels-idx1-ubyte rename to 12_knn/t10k-labels-idx1-ubyte diff --git a/10_knn/train-images-idx3-ubyte b/12_knn/train-images-idx3-ubyte similarity index 100% rename from 10_knn/train-images-idx3-ubyte rename to 12_knn/train-images-idx3-ubyte diff --git a/10_knn/train-labels-idx1-ubyte b/12_knn/train-labels-idx1-ubyte similarity index 100% rename from 10_knn/train-labels-idx1-ubyte rename to 12_knn/train-labels-idx1-ubyte diff --git a/README.md b/README.md index 9246b147..7d130980 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This is the code in my book [Grokking Algorithms](https://www.manning.com/bhargava). -Also check out [Python Tutor](http://pythontutor.com/), a great website that helps you step through Python code line by line. +Check out [Python Tutor](http://pythontutor.com/), a great website that guides you through Python code line by line. ## Errata @@ -10,9 +10,23 @@ Also check out [Python Tutor](http://pythontutor.com/), a great website that hel ## Images -This repo also contains every image in Grokking Algorithms, in hi-res. These images are available for free for non-commercial use. If you use an image, please add "copyright Manning Publications, drawn by adit.io". You are welcome to use these images in any non-commercial teaching materials, presentations, etc. +This repository contains every image in Grokking Algorithms in high resolution. These images are available for non-commercial use. If you use an image, please add "copyright Manning Publications, drawn by adit.io". You are welcome to use these images in any non-commercial materials (i.e. teaching materials, presentations, etc.) ## Contributing -- The examples in this book are in Python, but I'd like to get examples in Ruby, JavaScript, C, and other languages too. Please add examples in other languages! -- I'm pretty responsive to PRs. That is the quickest way to contribute to this repo. +Thanks for wanting to contribute to this repo! + +If you have found a mistake in the book or have a question, please email me as that will be the best way to get a response. My email is listed on my website, adit.io. +If you would like to make a change, please go ahead and open a PR with your suggested change. I am quicker at responding to those than I am to issues. + +It takes me a long time to respond to PRs. It's something I'm trying to get better at, but I apologize in advance for how long it will take. I will eventually get to it. + +The contributions that are most useful are: +- fixing errors in existing code +- adding examples to new languages +- modernizing code as the language evolves +- making code easier to read. + +I'm less likely to merge code that involves stylistic changes, and I'm very unlikely to merge PRs that add complex optimizations, as the main purpose of this repo is to have easy to read examples that help people understand concepts. + +Thanks for contributing and I hope you're enjoying the book! \ No newline at end of file