Skip to content

Commit 2abe7aa

Browse files
author
Quentin Ménoret
committed
Solution for binary-search-tree
1 parent e948a8e commit 2abe7aa

File tree

6 files changed

+311
-0
lines changed

6 files changed

+311
-0
lines changed

binary-search-tree/README.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Binary Search Tree
2+
3+
Insert and search for numbers in a binary tree.
4+
5+
When we need to represent sorted data, an array does not make a good
6+
data structure.
7+
8+
Say we have the array `[1, 3, 4, 5]`, and we add 2 to it so it becomes
9+
`[1, 3, 4, 5, 2]` now we must sort the entire array again! We can
10+
improve on this by realizing that we only need to make space for the new
11+
item `[1, nil, 3, 4, 5]`, and then adding the item in the space we
12+
added. But this still requires us to shift many elements down by one.
13+
14+
Binary Search Trees, however, can operate on sorted data much more
15+
efficiently.
16+
17+
A binary search tree consists of a series of connected nodes. Each node
18+
contains a piece of data (e.g. the number 3), a variable named `left`,
19+
and a variable named `right`. The `left` and `right` variables point at
20+
`nil`, or other nodes. Since these other nodes in turn have other nodes
21+
beneath them, we say that the left and right variables are pointing at
22+
subtrees. All data in the left subtree is less than or equal to the
23+
current node's data, and all data in the right subtree is greater than
24+
the current node's data.
25+
26+
For example, if we had a node containing the data 4, and we added the
27+
data 2, our tree would look like this:
28+
29+
4
30+
/
31+
2
32+
33+
If we then added 6, it would look like this:
34+
35+
4
36+
/ \
37+
2 6
38+
39+
If we then added 3, it would look like this
40+
41+
4
42+
/ \
43+
2 6
44+
\
45+
3
46+
47+
And if we then added 1, 5, and 7, it would look like this
48+
49+
4
50+
/ \
51+
/ \
52+
2 6
53+
/ \ / \
54+
1 3 5 7
55+
56+
## Hints
57+
58+
To complete this exercise you need to create the data type `BST`,
59+
with `Eq` and `Show` instances, and implement the functions:
60+
61+
- `bstLeft`
62+
- `bstRight`
63+
- `bstValue`
64+
- `empty`
65+
- `fromList`
66+
- `insert`
67+
- `singleton`
68+
- `toList`
69+
70+
You will find a dummy data declaration and type signatures already in place,
71+
but it is up to you to define the functions and create a meaningful data type,
72+
newtype or type synonym.
73+
74+
75+
## Getting Started
76+
77+
For installation and learning resources, refer to the
78+
[exercism help page](http://exercism.io/languages/haskell).
79+
80+
## Running the tests
81+
82+
To run the test suite, execute the following command:
83+
84+
```bash
85+
stack test
86+
```
87+
88+
#### If you get an error message like this...
89+
90+
```
91+
No .cabal file found in directory
92+
```
93+
94+
You are probably running an old stack version and need
95+
to upgrade it.
96+
97+
#### Otherwise, if you get an error message like this...
98+
99+
```
100+
No compiler found, expected minor version match with...
101+
Try running "stack setup" to install the correct GHC...
102+
```
103+
104+
Just do as it says and it will download and install
105+
the correct compiler version:
106+
107+
```bash
108+
stack setup
109+
```
110+
111+
## Running *GHCi*
112+
113+
If you want to play with your solution in GHCi, just run the command:
114+
115+
```bash
116+
stack ghci
117+
```
118+
119+
## Feedback, Issues, Pull Requests
120+
121+
The [exercism/xhaskell](https://github.com/exercism/xhaskell) repository on
122+
GitHub is the home for all of the Haskell exercises.
123+
124+
If you have feedback about an exercise, or want to help implementing a new
125+
one, head over there and create an issue. We'll do our best to help you!
126+
127+
## Source
128+
129+
Josh Cheek [https://twitter.com/josh_cheek](https://twitter.com/josh_cheek)
130+
131+
## Submitting Incomplete Problems
132+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
133+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
-- This file has been generated from package.yaml by hpack version 0.15.0.
2+
--
3+
-- see: https://github.com/sol/hpack
4+
5+
name: binary-search-tree
6+
version: 0.0.0
7+
build-type: Simple
8+
cabal-version: >= 1.10
9+
10+
library
11+
hs-source-dirs:
12+
src
13+
build-depends:
14+
base
15+
exposed-modules:
16+
BST
17+
other-modules:
18+
Paths_binary_search_tree
19+
default-language: Haskell2010
20+
21+
test-suite test
22+
type: exitcode-stdio-1.0
23+
main-is: Tests.hs
24+
hs-source-dirs:
25+
test
26+
build-depends:
27+
base
28+
, binary-search-tree
29+
, hspec
30+
default-language: Haskell2010

binary-search-tree/package.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: binary-search-tree
2+
3+
dependencies:
4+
- base
5+
6+
library:
7+
exposed-modules: BST
8+
source-dirs: src
9+
dependencies:
10+
# - foo # List here the packages you
11+
# - bar # want to use in your solution.
12+
13+
tests:
14+
test:
15+
main: Tests.hs
16+
source-dirs: test
17+
dependencies:
18+
- binary-search-tree
19+
- hspec

binary-search-tree/src/BST.hs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
module BST
2+
( BST
3+
, bstLeft
4+
, bstRight
5+
, bstValue
6+
, empty
7+
, fromList
8+
, insert
9+
, singleton
10+
, toList
11+
) where
12+
13+
data BST a = BST { left :: BST a
14+
, right :: BST a
15+
, value :: a
16+
}
17+
| Empty
18+
deriving (Eq, Show)
19+
20+
bstLeft :: BST a -> Maybe (BST a)
21+
bstLeft BST {left=Empty} = Nothing
22+
bstLeft BST {left=l} = Just l
23+
24+
bstRight :: BST a -> Maybe (BST a)
25+
bstRight BST {right=Empty} = Nothing
26+
bstRight BST {right=r} = Just r
27+
28+
bstValue :: BST a -> Maybe a
29+
bstValue Empty = Nothing
30+
bstValue BST {value=x} = Just x
31+
32+
empty :: BST a
33+
empty = Empty
34+
35+
fromList :: Ord a => [a] -> BST a
36+
fromList [] = Empty
37+
fromList (x:xs) = foldl (flip insert) (singleton x) xs
38+
39+
insert :: Ord a => a -> BST a -> BST a
40+
insert x BST {right=r, left=l, value=v}
41+
| v >= x = BST{left=insert x l, right=r, value=v}
42+
| otherwise = BST{left=l, right=insert x r, value=v}
43+
insert x empty = singleton x
44+
45+
singleton :: a -> BST a
46+
singleton x = BST {left=empty, right=empty, value=x}
47+
48+
toList :: BST a -> [a]
49+
toList Empty = []
50+
toList BST{left=l, right=r, value=v} = toList l ++ (v:toList r)

binary-search-tree/stack.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
resolver: lts-8.2

binary-search-tree/test/Tests.hs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import Test.Hspec (Spec, describe, it, shouldBe)
2+
import Test.Hspec.Runner (configFastFail, defaultConfig, hspecWith)
3+
4+
import BST
5+
( bstLeft
6+
, bstRight
7+
, bstValue
8+
, empty
9+
, fromList
10+
, insert
11+
, singleton
12+
, toList
13+
)
14+
15+
main :: IO ()
16+
main = hspecWith defaultConfig {configFastFail = True} specs
17+
18+
specs :: Spec
19+
specs = describe "binary-seach-tree" $ do
20+
21+
-- As of 2016-08-03, there was no reference file
22+
-- for the test cases in `exercism/x-common`.
23+
24+
let int4 = 4 :: Int
25+
let noInts = [] :: [Int]
26+
27+
it "data is retained" $
28+
bstValue (singleton int4) `shouldBe` Just 4
29+
30+
it "inserting less" $ do
31+
let t = insert 2 (singleton int4)
32+
bstValue t `shouldBe` Just 4
33+
(bstLeft t >>= bstValue) `shouldBe` Just 2
34+
35+
it "inserting same" $ do
36+
let t = insert 4 (singleton int4)
37+
bstValue t `shouldBe` Just 4
38+
(bstLeft t >>= bstValue) `shouldBe` Just 4
39+
40+
it "inserting right" $ do
41+
let t = insert 5 (singleton int4)
42+
bstValue t `shouldBe` Just 4
43+
(bstRight t >>= bstValue) `shouldBe` Just 5
44+
45+
it "empty list to tree" $
46+
fromList noInts `shouldBe` empty
47+
48+
it "empty list has no value" $
49+
bstValue (fromList noInts) `shouldBe` Nothing
50+
51+
it "inserting into empty" $ do
52+
let t = insert int4 empty
53+
bstValue t `shouldBe` Just 4
54+
55+
it "complex tree" $ do
56+
let t = fromList [int4, 2, 6, 1, 3, 7, 5]
57+
bstValue t `shouldBe` Just 4
58+
(bstLeft t >>= bstValue ) `shouldBe` Just 2
59+
(bstLeft t >>= bstLeft >>= bstValue) `shouldBe` Just 1
60+
(bstLeft t >>= bstRight >>= bstValue) `shouldBe` Just 3
61+
(bstRight t >>= bstValue ) `shouldBe` Just 6
62+
(bstRight t >>= bstLeft >>= bstValue) `shouldBe` Just 5
63+
(bstRight t >>= bstRight >>= bstValue) `shouldBe` Just 7
64+
65+
it "empty tree to list" $
66+
length (toList empty) `shouldBe` 0
67+
68+
it "iterating one element" $
69+
toList (singleton int4) `shouldBe` [4]
70+
71+
it "iterating over smaller element" $
72+
toList (fromList [int4, 2]) `shouldBe` [2, 4]
73+
74+
it "iterating over larger element" $
75+
toList (fromList [int4, 5]) `shouldBe` [4, 5]
76+
77+
it "iterating over complex tree" $
78+
toList (fromList [int4, 2, 1, 3, 6, 7, 5]) `shouldBe` [1..7]

0 commit comments

Comments
 (0)