-
-
Notifications
You must be signed in to change notification settings - Fork 191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implementing exercise binary-search #615
Changes from 4 commits
078f092
c26de9e
f5bbc8a
0b6c2d6
cadc26a
f1ba38c
6356637
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# Binary Search | ||
|
||
Implement a binary search algorithm. | ||
|
||
Searching a sorted collection is a common task. A dictionary is a sorted list of word definitions. Given a word, one can find its definition. A telephone book is a sorted list of people's names, addresses, and telephone numbers. Knowing someone's name allows one to quickly find their telephone number and address. | ||
|
||
If the list to be searched contains more than a few items (a dozen, say) a binary search will require far fewer comparisons than a linear search, but it imposes the requirement that the list be sorted. | ||
|
||
In computer science, a binary search or half-interval search algorithm finds the position of a specified input value (the search "key") within an array sorted by key value. | ||
|
||
In each step, the algorithm compares the search key value with the key value of the middle element of the array. | ||
|
||
If the keys match, then a matching element has been found and its index, is returned. | ||
|
||
Otherwise, if the search key is less than the middle element's key, then the algorithm repeats its action on the sub-array to the left of the middle element or, if the search key is greater, on the sub-array to the right. | ||
|
||
If the remaining array to be searched is empty, then the key cannot be found in the array and Nothing is returned. | ||
|
||
A binary search halves the number of items to check with each iteration, so locating an item (or determining its absence) takes logarithmic time. A binary search is a dichotomic divide and conquer search algorithm. | ||
|
||
|
||
## Getting Started | ||
|
||
For installation and learning resources, refer to the | ||
[exercism help page](http://exercism.io/languages/haskell). | ||
|
||
## Running the tests | ||
|
||
To run the test suite, execute the following command: | ||
|
||
```bash | ||
stack test | ||
``` | ||
|
||
#### If you get an error message like this... | ||
|
||
``` | ||
No .cabal file found in directory | ||
``` | ||
|
||
You are probably running an old stack version and need | ||
to upgrade it. | ||
|
||
#### Otherwise, if you get an error message like this... | ||
|
||
``` | ||
No compiler found, expected minor version match with... | ||
Try running "stack setup" to install the correct GHC... | ||
``` | ||
|
||
Just do as it says and it will download and install | ||
the correct compiler version: | ||
|
||
```bash | ||
stack setup | ||
``` | ||
|
||
## Running *GHCi* | ||
|
||
If you want to play with your solution in GHCi, just run the command: | ||
|
||
```bash | ||
stack ghci | ||
``` | ||
|
||
## Feedback, Issues, Pull Requests | ||
|
||
The [exercism/haskell](https://github.com/exercism/haskell) repository on | ||
GitHub is the home for all of the Haskell exercises. | ||
|
||
If you have feedback about an exercise, or want to help implementing a new | ||
one, head over there and create an issue. We'll do our best to help you! | ||
|
||
## Source | ||
|
||
Wikipedia [https://en.wikipedia.org/wiki/Isogram](https://en.wikipedia.org/wiki/Isogram) | ||
|
||
## Submitting Incomplete Solutions | ||
It's possible to submit an incomplete solution so you can see how others have completed the exercise. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
name: binary-search | ||
|
||
dependencies: | ||
- base | ||
- array | ||
|
||
library: | ||
exposed-modules: BinarySearch | ||
source-dirs: src | ||
|
||
tests: | ||
test: | ||
main: Tests.hs | ||
source-dirs: test | ||
dependencies: | ||
- binary-search | ||
- hspec |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
module BinarySearch (binarySearch) where | ||
import Data.Array (Array, (!), elems, listArray) | ||
import Data.Maybe (isJust, fromJust) | ||
|
||
binarySearch :: (Eq a, Ord a) => Array Int a -> a -> Maybe Int | ||
binarySearch arr x | ||
| null arr = Nothing | ||
| length arr == 1 = if arr ! 0 == x then Just 0 else Nothing | ||
| x < (arr ! 0) || x > (arr ! (length arr - 1)) = Nothing | ||
| otherwise = let contents = elems arr | ||
middle = length contents `div` 2 | ||
(farr, sarr) = splitAt middle contents | ||
fhalf = listArray (0, length farr - 1) farr | ||
shalf = listArray (0, length sarr - 1) sarr | ||
target = if x >= head sarr then shalf else fhalf | ||
res = binarySearch target x in | ||
if isJust res && target == shalf | ||
then Just ((fromJust res) + middle) else res |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
name: binary-search | ||
version: 1.0.0 | ||
|
||
dependencies: | ||
- array | ||
- base | ||
|
||
library: | ||
exposed-modules: BinarySearch | ||
source-dirs: src | ||
dependencies: | ||
# - foo # List here the packages you | ||
# - bar # want to use in your solution. | ||
|
||
tests: | ||
test: | ||
main: Tests.hs | ||
source-dirs: test | ||
dependencies: | ||
- binary-search | ||
- hspec |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module BinarySearch (binarySearch) where | ||
import Data.Array (Array) | ||
|
||
binarySearch :: Array Int Int -> Int -> Maybe Int | ||
binarySearch = error "You need to implement this function!" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
resolver: lts-9.11 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
{-# LANGUAGE RecordWildCards #-} | ||
|
||
import Data.Foldable (for_) | ||
import Test.Hspec (Spec, describe, it, shouldBe) | ||
import Test.Hspec.Runner (configFastFail, defaultConfig, hspecWith) | ||
import Data.Array (Array, listArray) | ||
|
||
import BinarySearch (binarySearch) | ||
|
||
main :: IO () | ||
main = hspecWith defaultConfig {configFastFail = True} specs | ||
|
||
specs :: Spec | ||
specs = describe "foundElement" $ for_ cases test | ||
where | ||
test Case{..} = it description assertion | ||
where | ||
assertion = binarySearch input value `shouldBe` expected | ||
|
||
|
||
data Case a = Case { description :: String | ||
, input :: Array Int a | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would indent this line two spaces further so that the comma lines up with the open bracket on the previous row. |
||
, value :: a | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
same |
||
, expected :: Maybe Int | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
same |
||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
same except now I'm talking about the closing bracket |
||
|
||
cases :: [Case Int] | ||
cases = [ Case { description = "finds a value in an array with one element" | ||
, input = listArray (0, 0) [6] | ||
, value = 6 | ||
, expected = Just 0 | ||
} | ||
, Case { description = "finds a value in the middle of an array" | ||
, input = array1 | ||
, value = 6 | ||
, expected = Just 3 | ||
} | ||
, Case { description = "finds a value at the beginning of an array" | ||
, input = array1 | ||
, value = 1 | ||
, expected = Just 0 | ||
} | ||
, Case { description = "finds a value at the end of an array" | ||
, input = array1 | ||
, value = 11 | ||
, expected = Just 6 | ||
} | ||
, Case { description = "finds a value in an array of odd length" | ||
, input = listArray (0, 12) [1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 634] | ||
, value = 144 | ||
, expected = Just 9 | ||
} | ||
, Case { description = "finds a value in an array of even length" | ||
, input = listArray (0, 11) [1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377] | ||
, value = 21 | ||
, expected = Just 5 | ||
} | ||
, Case { description = "a value smaller than the array's smallest value is not included" | ||
, input = array1 | ||
, value = 0 | ||
, expected = Nothing | ||
} | ||
, Case { description = "a value larger than the array's largest value is not included" | ||
, input = array1 | ||
, value = 13 | ||
, expected = Nothing | ||
} | ||
, Case { description = "nothing is included in an empty array" | ||
, input = listArray (1, 0) [] -- There is no way to represent an empty array | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ignore the dumb comment, there is. it is working |
||
, value = 1 | ||
, expected = Nothing | ||
} | ||
] | ||
where array1 = listArray (0, 6) [1, 3, 4, 6, 8, 9, 11] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm considering whether this should go above the cases so that I can see it before I see the cases it's going to be used in. I'm not sure, so let me know what you think about it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why isogram?