Skip to content

Commit 1ffb872

Browse files
authored
Add binary-search-tree (#386)
1 parent 4fff23a commit 1ffb872

8 files changed

Lines changed: 343 additions & 2 deletions

File tree

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,14 @@
654654
"strings"
655655
]
656656
},
657+
{
658+
"slug": "binary-search-tree",
659+
"name": "Binary Search Tree",
660+
"uuid": "4e8df8d7-2ca6-4c2b-9e0f-1f6a05ac8c57",
661+
"practices": [],
662+
"prerequisites": [],
663+
"difficulty": 5
664+
},
657665
{
658666
"slug": "camicia",
659667
"name": "Camicia",
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Instructions
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 data structure.
6+
7+
Say we have the array `[1, 3, 4, 5]`, and we add 2 to it so it becomes `[1, 3, 4, 5, 2]`.
8+
Now we must sort the entire array again!
9+
We can improve on this by realizing that we only need to make space for the new item `[1, nil, 3, 4, 5]`, and then adding the item in the space we added.
10+
But this still requires us to shift many elements down by one.
11+
12+
Binary Search Trees, however, can operate on sorted data much more efficiently.
13+
14+
A binary search tree consists of a series of connected nodes.
15+
Each node contains a piece of data (e.g. the number 3), a variable named `left`, and a variable named `right`.
16+
The `left` and `right` variables point at `nil`, or other nodes.
17+
Since these other nodes in turn have other nodes beneath them, we say that the left and right variables are pointing at subtrees.
18+
All data in the left subtree is less than or equal to the current node's data, and all data in the right subtree is greater than the current node's data.
19+
20+
For example, if we had a node containing the data 4, and we added the data 2, our tree would look like this:
21+
22+
![A graph with root node 4 and a single child node 2.](https://assets.exercism.org/images/exercises/binary-search-tree/tree-4-2.svg)
23+
24+
```text
25+
4
26+
/
27+
2
28+
```
29+
30+
If we then added 6, it would look like this:
31+
32+
![A graph with root node 4 and two child nodes 2 and 6.](https://assets.exercism.org/images/exercises/binary-search-tree/tree-4-2-6.svg)
33+
34+
```text
35+
4
36+
/ \
37+
2 6
38+
```
39+
40+
If we then added 3, it would look like this
41+
42+
![A graph with root node 4, two child nodes 2 and 6, and a grandchild node 3.](https://assets.exercism.org/images/exercises/binary-search-tree/tree-4-2-6-3.svg)
43+
44+
```text
45+
4
46+
/ \
47+
2 6
48+
\
49+
3
50+
```
51+
52+
And if we then added 1, 5, and 7, it would look like this
53+
54+
![A graph with root node 4, two child nodes 2 and 6, and four grandchild nodes 1, 3, 5 and 7.](https://assets.exercism.org/images/exercises/binary-search-tree/tree-4-2-6-1-3-5-7.svg)
55+
56+
```text
57+
4
58+
/ \
59+
/ \
60+
2 6
61+
/ \ / \
62+
1 3 5 7
63+
```
64+
65+
## Credit
66+
67+
The images were created by [habere-et-dispertire][habere-et-dispertire] using [PGF/TikZ][pgf-tikz] by Till Tantau.
68+
69+
[habere-et-dispertire]: https://exercism.org/profiles/habere-et-dispertire
70+
[pgf-tikz]: https://en.wikipedia.org/wiki/PGF/TikZ
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"authors": [
3+
"BNAndras"
4+
],
5+
"files": {
6+
"solution": [
7+
"binary_search_tree.vim"
8+
],
9+
"test": [
10+
"binary_search_tree.vader"
11+
],
12+
"example": [
13+
".meta/example.vim"
14+
]
15+
},
16+
"blurb": "Insert and search for numbers in a binary tree.",
17+
"source": "Josh Cheek"
18+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
function! Data(treeData) abort
2+
if empty(a:treeData)
3+
return v:null
4+
endif
5+
6+
let l:tree = s:Node(a:treeData[0])
7+
for l:value in a:treeData[1:]
8+
let l:tree = s:Insert(l:tree, l:value)
9+
endfor
10+
11+
return l:tree
12+
endfunction
13+
14+
function! SortedData(treeData) abort
15+
return s:InOrder(Data(a:treeData))
16+
endfunction
17+
18+
function! s:Insert(tree, value) abort
19+
if a:tree is v:null
20+
return s:Node(a:value)
21+
endif
22+
23+
if a:value <=# a:tree.data
24+
let a:tree.left = s:Insert(a:tree.left, a:value)
25+
else
26+
let a:tree.right = s:Insert(a:tree.right, a:value)
27+
endif
28+
29+
return a:tree
30+
endfunction
31+
32+
function! s:Node(value) abort
33+
return {'data': a:value, 'left': v:null, 'right': v:null}
34+
endfunction
35+
36+
function! s:InOrder(tree) abort
37+
if a:tree is v:null
38+
return []
39+
endif
40+
41+
return s:InOrder(a:tree.left) + [a:tree.data] + s:InOrder(a:tree.right)
42+
endfunction
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[e9c93a78-c536-4750-a336-94583d23fafa]
13+
description = "data is retained"
14+
15+
[7a95c9e8-69f6-476a-b0c4-4170cb3f7c91]
16+
description = "smaller number at left node"
17+
18+
[22b89499-9805-4703-a159-1a6e434c1585]
19+
description = "same number at left node"
20+
21+
[2e85fdde-77b1-41ed-b6ac-26ce6b663e34]
22+
description = "greater number at right node"
23+
24+
[dd898658-40ab-41d0-965e-7f145bf66e0b]
25+
description = "can create complex tree"
26+
27+
[9e0c06ef-aeca-4202-b8e4-97f1ed057d56]
28+
description = "can sort single number"
29+
30+
[425e6d07-fceb-4681-a4f4-e46920e380bb]
31+
description = "can sort if second number is smaller than first"
32+
33+
[bd7532cc-6988-4259-bac8-1d50140079ab]
34+
description = "can sort if second number is same as first"
35+
36+
[b6d1b3a5-9d79-44fd-9013-c83ca92ddd36]
37+
description = "can sort if second number is greater than first"
38+
39+
[d00ec9bd-1288-4171-b968-d44d0808c1c8]
40+
description = "can sort complex tree"
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
Execute (data is retained):
2+
let g:treeData = ['4']
3+
let g:expected = {'data': '4', 'left': v:null, 'right': v:null}
4+
AssertEqual g:expected, Data(g:treeData)
5+
6+
Execute (smaller number at left node):
7+
let g:treeData = ['4', '2']
8+
let g:expected = {
9+
\ 'data': '4',
10+
\ 'left': {
11+
\ 'data': '2',
12+
\ 'left': v:null,
13+
\ 'right': v:null
14+
\ },
15+
\ 'right': v:null
16+
\ }
17+
AssertEqual g:expected, Data(g:treeData)
18+
19+
Execute (same number at left node):
20+
let g:treeData = ['4', '4']
21+
let g:expected = {
22+
\ 'data': '4',
23+
\ 'left': {
24+
\ 'data': '4',
25+
\ 'left': v:null,
26+
\ 'right': v:null
27+
\ },
28+
\ 'right': v:null
29+
\ }
30+
AssertEqual g:expected, Data(g:treeData)
31+
32+
Execute (greater number at right node):
33+
let g:treeData = ['4', '5']
34+
let g:expected = {
35+
\ 'data': '4',
36+
\ 'left': v:null,
37+
\ 'right': {
38+
\ 'data': '5',
39+
\ 'left': v:null,
40+
\ 'right': v:null
41+
\ }
42+
\ }
43+
AssertEqual g:expected, Data(g:treeData)
44+
45+
Execute (can create complex tree):
46+
let g:treeData = ['4', '2', '6', '1', '3', '5', '7']
47+
let g:expected = {
48+
\ 'data': '4',
49+
\ 'left': {
50+
\ 'data': '2',
51+
\ 'left': {
52+
\ 'data': '1',
53+
\ 'left': v:null,
54+
\ 'right': v:null
55+
\ },
56+
\ 'right': {
57+
\ 'data': '3',
58+
\ 'left': v:null,
59+
\ 'right': v:null
60+
\ }
61+
\ },
62+
\ 'right': {
63+
\ 'data': '6',
64+
\ 'left': {
65+
\ 'data': '5',
66+
\ 'left': v:null,
67+
\ 'right': v:null
68+
\ },
69+
\ 'right': {
70+
\ 'data': '7',
71+
\ 'left': v:null,
72+
\ 'right': v:null
73+
\ }
74+
\ }
75+
\ }
76+
AssertEqual g:expected, Data(g:treeData)
77+
78+
Execute (can sort single number):
79+
let g:treeData = ['2']
80+
let g:expected = ['2']
81+
AssertEqual g:expected, SortedData(g:treeData)
82+
83+
Execute (can sort if second number is smaller than first):
84+
let g:treeData = ['2', '1']
85+
let g:expected = ['1', '2']
86+
AssertEqual g:expected, SortedData(g:treeData)
87+
88+
Execute (can sort if second number is same as first):
89+
let g:treeData = ['2', '2']
90+
let g:expected = ['2', '2']
91+
AssertEqual g:expected, SortedData(g:treeData)
92+
93+
Execute (can sort if second number is greater than first):
94+
let g:treeData = ['2', '3']
95+
let g:expected = ['2', '3']
96+
AssertEqual g:expected, SortedData(g:treeData)
97+
98+
Execute (can sort complex tree):
99+
let g:treeData = ['2', '1', '3', '6', '7', '5']
100+
let g:expected = ['1', '2', '3', '5', '6', '7']
101+
AssertEqual g:expected, SortedData(g:treeData)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
"
2+
" Insert a sequence of values into a binary search tree and return the tree
3+
" or its data in sorted order.
4+
"
5+
function! Data(treeData) abort
6+
" your solution goes here
7+
endfunction
8+
9+
function! SortedData(treeData) abort
10+
" your solution goes here
11+
endfunction

lib/generate.vim

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,59 @@ function! s:filter_test_cases(cases, excluded_uuids) abort
113113
return filtered
114114
endfunction
115115

116-
function! s:generate_variable(name, value)
117-
call append(line('$'), printf(' let g:%s = %s', a:name, string(a:value)))
116+
function! s:dict_literal(dict) abort
117+
if empty(a:dict)
118+
return ['{}']
119+
endif
120+
121+
let lines = ['{']
122+
let key_names = sort(keys(a:dict))
123+
let last_key = key_names[-1]
124+
125+
for key_name in key_names
126+
let key_fragment = string(key_name) . ': '
127+
let value = a:dict[key_name]
128+
129+
if type(value) ==# type({})
130+
let entry_lines = s:dict_literal(value)
131+
let entry_lines[0] = key_fragment . entry_lines[0]
132+
else
133+
let entry_lines = [key_fragment . string(value)]
134+
endif
135+
136+
let entry_lines = s:indent_lines(entry_lines)
137+
if key_name !=# last_key
138+
let entry_lines[-1] .= ','
139+
endif
140+
call extend(lines, entry_lines)
141+
endfor
142+
143+
call add(lines, '}')
144+
return lines
145+
endfunction
146+
147+
function! s:indent_lines(lines) abort
148+
let indented = []
149+
for line in a:lines
150+
call add(indented, ' ' . line)
151+
endfor
152+
return indented
153+
endfunction
154+
155+
function! s:generate_variable(name, value) abort
156+
let binding = printf(' let g:%s = ', a:name)
157+
let inline = binding . string(a:value)
158+
159+
if strdisplaywidth(inline) <= 80 || type(a:value) !=# type({})
160+
call append(line('$'), inline)
161+
return
162+
endif
163+
164+
let value_lines = s:dict_literal(a:value)
165+
call append(line('$'), binding . value_lines[0])
166+
for line in value_lines[1:]
167+
call append(line('$'), ' \ ' . line)
168+
endfor
118169
endfunction
119170

120171
function! s:generate_assert(test, arguments) abort

0 commit comments

Comments
 (0)