diff --git a/config.json b/config.json index dea0e10..bbb2f7d 100644 --- a/config.json +++ b/config.json @@ -438,6 +438,14 @@ "practices": [], "prerequisites": [], "difficulty": 6 + }, + { + "slug": "binary-search", + "name": "Binary Search", + "uuid": "fa1bd1bc-a6c4-426a-bbf6-2cd0cc711e31", + "practices": [], + "prerequisites": [], + "difficulty": 4 } ] }, diff --git a/exercises/practice/binary-search/.docs/instructions.md b/exercises/practice/binary-search/.docs/instructions.md new file mode 100644 index 0000000..12f4358 --- /dev/null +++ b/exercises/practice/binary-search/.docs/instructions.md @@ -0,0 +1,29 @@ +# Instructions + +Your task is to implement a binary search algorithm. + +A binary search algorithm finds an item in a list by repeatedly splitting it in half, only keeping the half which contains the item we're looking for. +It allows us to quickly narrow down the possible locations of our item until we find it, or until we've eliminated all possible locations. + +~~~~exercism/caution +Binary search only works when a list has been sorted. +~~~~ + +The algorithm looks like this: + +- Find the middle element of a _sorted_ list and compare it with the item we're looking for. +- If the middle element is our item, then we're done! +- If the middle element is greater than our item, we can eliminate that element and all the elements **after** it. +- If the middle element is less than our item, we can eliminate that element and all the elements **before** it. +- If every element of the list has been eliminated then the item is not in the list. +- Otherwise, repeat the process on the part of the list that has not been eliminated. + +Here's an example: + +Let's say we're looking for the number 23 in the following sorted list: `[4, 8, 12, 16, 23, 28, 32]`. + +- We start by comparing 23 with the middle element, 16. +- Since 23 is greater than 16, we can eliminate the left half of the list, leaving us with `[23, 28, 32]`. +- We then compare 23 with the new middle element, 28. +- Since 23 is less than 28, we can eliminate the right half of the list: `[23]`. +- We've found our item. diff --git a/exercises/practice/binary-search/.docs/introduction.md b/exercises/practice/binary-search/.docs/introduction.md new file mode 100644 index 0000000..0349659 --- /dev/null +++ b/exercises/practice/binary-search/.docs/introduction.md @@ -0,0 +1,13 @@ +# Introduction + +You have stumbled upon a group of mathematicians who are also singer-songwriters. +They have written a song for each of their favorite numbers, and, as you can imagine, they have a lot of favorite numbers (like [0][zero] or [73][seventy-three] or [6174][kaprekars-constant]). + +You are curious to hear the song for your favorite number, but with so many songs to wade through, finding the right song could take a while. +Fortunately, they have organized their songs in a playlist sorted by the title — which is simply the number that the song is about. + +You realize that you can use a binary search algorithm to quickly find a song given the title. + +[zero]: https://en.wikipedia.org/wiki/0 +[seventy-three]: https://en.wikipedia.org/wiki/73_(number) +[kaprekars-constant]: https://en.wikipedia.org/wiki/6174_(number) diff --git a/exercises/practice/binary-search/.meta/config.json b/exercises/practice/binary-search/.meta/config.json new file mode 100644 index 0000000..3c666fc --- /dev/null +++ b/exercises/practice/binary-search/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "SimaDovakin" + ], + "files": { + "solution": [ + "binarySearch.u" + ], + "test": [ + "binarySearch.test.u" + ], + "example": [ + ".meta/examples/binarySearch.example.u" + ] + }, + "blurb": "Implement a binary search algorithm.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Binary_search_algorithm" +} diff --git a/exercises/practice/binary-search/.meta/examples/binarySearch.example.u b/exercises/practice/binary-search/.meta/examples/binarySearch.example.u new file mode 100644 index 0000000..17759a3 --- /dev/null +++ b/exercises/practice/binary-search/.meta/examples/binarySearch.example.u @@ -0,0 +1,17 @@ +use data Array + +binarySearch.find : Array Nat -> Nat -> Optional Int +binarySearch.find array target = + binSearch array target +0 (size array - 1 |> toInt) + +binarySearch.binSearch : Array Nat -> Nat -> Int -> Int -> Optional Int +binarySearch.binSearch arr val = cases + startIndex, endIndex | endIndex < startIndex -> None + startIndex, endIndex -> + midIndex = (startIndex + endIndex) / +2 + match at (toNat midIndex |> getOrElse 0) arr with + None -> None + Some v -> match ordering v val with + Equal -> Some midIndex + Less -> binSearch arr val (midIndex + +1) endIndex + Greater -> binSearch arr val startIndex (midIndex - +1) diff --git a/exercises/practice/binary-search/.meta/testAnnotation.json b/exercises/practice/binary-search/.meta/testAnnotation.json new file mode 100644 index 0000000..b2e5c3c --- /dev/null +++ b/exercises/practice/binary-search/.meta/testAnnotation.json @@ -0,0 +1,46 @@ +[ + { + "name": "binarySearch.find.tests.ex1", + "test_code": "expect (Some +0 === binarySearch.find (Array.fromList [6]) 6)\n |> Test.label \"finds a value in an array with one element\"" + }, + { + "name": "binarySearch.find.tests.ex2", + "test_code": "expect (Some +3 === binarySearch.find (Array.fromList [1, 3, 4, 6, 8, 9, 11]) 6)\n |> Test.label \"finds a value in the middle of an array\"" + }, + { + "name": "binarySearch.find.tests.ex3", + "test_code": "expect (Some +0 === binarySearch.find (Array.fromList [1, 3, 4, 6, 8, 9, 11]) 1)\n |> Test.label \"finds a value at the beginning of an array\"" + }, + { + "name": "binarySearch.find.tests.ex4", + "test_code": "expect (Some +6 === binarySearch.find (Array.fromList [1, 3, 4, 6, 8, 9, 11]) 11)\n |> Test.label \"finds a value at the end of an array\"" + }, + { + "name": "binarySearch.find.tests.ex5", + "test_code": "expect (Some +9 === binarySearch.find (Array.fromList [1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 634]) 144)\n |> Test.label \"finds a value in an array of odd length\"" + }, + { + "name": "binarySearch.find.tests.ex6", + "test_code": "expect (Some +5 === binarySearch.find (Array.fromList [1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]) 21)\n |> Test.label \"finds a value in an array of even length\"" + }, + { + "name": "binarySearch.find.tests.ex7", + "test_code": "expect (None === binarySearch.find (Array.fromList [1, 3, 4, 6, 8, 9, 11]) 7)\n |> Test.label \"identifies that a value is not included in the array\"" + }, + { + "name": "binarySearch.find.tests.ex8", + "test_code": "expect (None === binarySearch.find (Array.fromList [1, 3, 4, 6, 8, 9, 11]) 0)\n |> Test.label \"a value smaller than the array's smallest value is not found\"" + }, + { + "name": "binarySearch.find.tests.ex9", + "test_code": "expect (None === binarySearch.find (Array.fromList [1, 3, 4, 6, 8, 9, 11]) 13)\n |> Test.label \"a value larger than the array's largest value is not found\"" + }, + { + "name": "binarySearch.find.tests.ex10", + "test_code": "expect (None === binarySearch.find (Array.fromList []) 1)\n |> Test.label \"nothing is found in an empty array\"" + }, + { + "name": "binarySearch.find.tests.ex11", + "test_code": "expect (None === binarySearch.find (Array.fromList [1, 2]) 0)\n |> Test.label \"nothing is found when the left and right bounds cross\"" + } +] diff --git a/exercises/practice/binary-search/.meta/testLoader.md b/exercises/practice/binary-search/.meta/testLoader.md new file mode 100644 index 0000000..943a4ad --- /dev/null +++ b/exercises/practice/binary-search/.meta/testLoader.md @@ -0,0 +1,9 @@ +# Testing transcript for binary-search exercise + +```ucm +.> load ./binarySearch.u +.> add +.> load ./binarySearch.test.u +.> add +.> move.term binarySearch.tests tests +``` diff --git a/exercises/practice/binary-search/.meta/tests.toml b/exercises/practice/binary-search/.meta/tests.toml new file mode 100644 index 0000000..61e2b06 --- /dev/null +++ b/exercises/practice/binary-search/.meta/tests.toml @@ -0,0 +1,43 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[b55c24a9-a98d-4379-a08c-2adcf8ebeee8] +description = "finds a value in an array with one element" + +[73469346-b0a0-4011-89bf-989e443d503d] +description = "finds a value in the middle of an array" + +[327bc482-ab85-424e-a724-fb4658e66ddb] +description = "finds a value at the beginning of an array" + +[f9f94b16-fe5e-472c-85ea-c513804c7d59] +description = "finds a value at the end of an array" + +[f0068905-26e3-4342-856d-ad153cadb338] +description = "finds a value in an array of odd length" + +[fc316b12-c8b3-4f5e-9e89-532b3389de8c] +description = "finds a value in an array of even length" + +[da7db20a-354f-49f7-a6a1-650a54998aa6] +description = "identifies that a value is not included in the array" + +[95d869ff-3daf-4c79-b622-6e805c675f97] +description = "a value smaller than the array's smallest value is not found" + +[8b24ef45-6e51-4a94-9eac-c2bf38fdb0ba] +description = "a value larger than the array's largest value is not found" + +[f439a0fa-cf42-4262-8ad1-64bf41ce566a] +description = "nothing is found in an empty array" + +[2c353967-b56d-40b8-acff-ce43115eed64] +description = "nothing is found when the left and right bounds cross" diff --git a/exercises/practice/binary-search/binarySearch.test.u b/exercises/practice/binary-search/binarySearch.test.u new file mode 100644 index 0000000..7aca1b8 --- /dev/null +++ b/exercises/practice/binary-search/binarySearch.test.u @@ -0,0 +1,59 @@ +use data Array + +binarySearch.find.tests.ex1 = + expect (Some +0 === binarySearch.find (Array.fromList [6]) 6) + |> Test.label "finds a value in an array with one element" + +binarySearch.find.tests.ex2 = + expect (Some +3 === binarySearch.find (Array.fromList [1, 3, 4, 6, 8, 9, 11]) 6) + |> Test.label "finds a value in the middle of an array" + +binarySearch.find.tests.ex3 = + expect (Some +0 === binarySearch.find (Array.fromList [1, 3, 4, 6, 8, 9, 11]) 1) + |> Test.label "finds a value at the beginning of an array" + +binarySearch.find.tests.ex4 = + expect (Some +6 === binarySearch.find (Array.fromList [1, 3, 4, 6, 8, 9, 11]) 11) + |> Test.label "finds a value at the end of an array" + +binarySearch.find.tests.ex5 = + expect (Some +9 === binarySearch.find (Array.fromList [1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 634]) 144) + |> Test.label "finds a value in an array of odd length" + +binarySearch.find.tests.ex6 = + expect (Some +5 === binarySearch.find (Array.fromList [1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]) 21) + |> Test.label "finds a value in an array of even length" + +binarySearch.find.tests.ex7 = + expect (None === binarySearch.find (Array.fromList [1, 3, 4, 6, 8, 9, 11]) 7) + |> Test.label "identifies that a value is not included in the array" + +binarySearch.find.tests.ex8 = + expect (None === binarySearch.find (Array.fromList [1, 3, 4, 6, 8, 9, 11]) 0) + |> Test.label "a value smaller than the array's smallest value is not found" + +binarySearch.find.tests.ex9 = + expect (None === binarySearch.find (Array.fromList [1, 3, 4, 6, 8, 9, 11]) 13) + |> Test.label "a value larger than the array's largest value is not found" + +binarySearch.find.tests.ex10 = + expect (None === binarySearch.find (Array.fromList []) 1) + |> Test.label "nothing is found in an empty array" + +binarySearch.find.tests.ex11 = + expect (None === binarySearch.find (Array.fromList [1, 2]) 0) + |> Test.label "nothing is found when the left and right bounds cross" + +test> binarySearch.tests = runAll [ + binarySearch.find.tests.ex1, + binarySearch.find.tests.ex2, + binarySearch.find.tests.ex3, + binarySearch.find.tests.ex4, + binarySearch.find.tests.ex5, + binarySearch.find.tests.ex6, + binarySearch.find.tests.ex7, + binarySearch.find.tests.ex8, + binarySearch.find.tests.ex9, + binarySearch.find.tests.ex10, + binarySearch.find.tests.ex11 +] diff --git a/exercises/practice/binary-search/binarySearch.u b/exercises/practice/binary-search/binarySearch.u new file mode 100644 index 0000000..d5aa403 --- /dev/null +++ b/exercises/practice/binary-search/binarySearch.u @@ -0,0 +1,4 @@ +use data Array + +binarySearch.find : Array Nat -> Nat -> Optional Int +binarySearch.find = todo "implement find"