Skip to content

Commit 860fadc

Browse files
committed
binary-search-tree: add new exercise
Signed-off-by: devkabiir <[email protected]>
1 parent a87d724 commit 860fadc

File tree

7 files changed

+259
-0
lines changed

7 files changed

+259
-0
lines changed

config.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,24 @@
216216
"pattern_matching",
217217
"stacks"
218218
]
219+
},
220+
{
221+
"slug": "binary-search-tree",
222+
"uuid": "597f86bc-6717-4a4c-a2c6-58241ac3d6cb",
223+
"core": true,
224+
"unlocked_by": null,
225+
"difficulty": 5,
226+
"topics": [
227+
"algorithms",
228+
"classes",
229+
"generics",
230+
"inheritance",
231+
"logic",
232+
"object_oriented_programming",
233+
"searching",
234+
"sorting",
235+
"trees"
236+
]
219237
}
220238
]
221239
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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+
## Resources
57+
58+
- [Data structures: Binary Search Tree (YouTube)](https://youtu.be/pYT9F8_LFTM?t=9m39s)
59+
60+
## Submitting Incomplete Solutions
61+
62+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
analyzer:
2+
strong-mode:
3+
implicit-casts: false
4+
implicit-dynamic: false
5+
errors:
6+
unused_element: error
7+
unused_import: error
8+
unused_local_variable: error
9+
dead_code: error
10+
11+
linter:
12+
rules:
13+
# Error Rules
14+
- avoid_relative_lib_imports
15+
- avoid_types_as_parameter_names
16+
- literal_only_boolean_expressions
17+
- no_adjacent_strings_in_list
18+
- valid_regexps
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class BinarySearchTree {
2+
// Put your code here
3+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
class BinarySearchTree<T extends Comparable<T>> {
2+
/// Root node for the tree.
3+
final Node<T> root;
4+
5+
BinarySearchTree(T rootData) : root = new Node<T>(rootData) {
6+
// Note: [assert] does not run in release mode
7+
assert(rootData != null);
8+
}
9+
10+
/// Returns an empty `List` if [root] is `null`.
11+
///
12+
/// Otherwise returns data traversed in ascending order.
13+
Iterable<T> get sortedData sync* {
14+
for (var t in root?.ascendingOrder ?? <T>[]) yield t;
15+
}
16+
17+
/// Returns `true` on success, `false` on failure.
18+
bool insert(T value) => root?.insert(value) ?? false;
19+
}
20+
21+
class Node<T extends Comparable<T>> {
22+
/// The actual Data this node holds which should be a [Comparable]
23+
final T data;
24+
25+
/// Left node of this node, can be `null`
26+
Node<T> left;
27+
28+
/// Right node of this node, can be `null`
29+
Node<T> right;
30+
31+
Node(this.data, [this.left, this.right]) {
32+
// Note: [assert] does not run in release mode
33+
assert(data != null);
34+
}
35+
36+
/// This is **inorder** traversal of the tree.
37+
Iterable<T> get ascendingOrder sync* {
38+
if (data == null) return;
39+
40+
/// Traverse left sub-tree if it's present
41+
for (var t in left?.ascendingOrder ?? <T>[]) yield t;
42+
43+
yield data;
44+
45+
/// Traverse right sub-tree if it's present
46+
for (var t in right?.ascendingOrder ?? <T>[]) yield t;
47+
}
48+
49+
/// Returns `true` on success, `false` on failure.
50+
bool insert(T value) {
51+
if (value == null) return false;
52+
53+
/// Insert in left sub-tree if its a smaller or equal number.
54+
if (value.compareTo(data) <= 0) {
55+
return left?.insert(value) ?? (left = new Node(value)).data == value;
56+
}
57+
58+
/// Insert in right sub-tree if its a greater number.
59+
return right?.insert(value) ?? (right = new Node(value)).data == value;
60+
}
61+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
name: 'binary_search_tree'
2+
environment:
3+
sdk: '>=1.24.0 <3.0.0'
4+
dev_dependencies:
5+
test: '<2.0.0'
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import 'package:binary_search_tree/binary_search_tree.dart';
2+
import 'package:test/test.dart';
3+
4+
void main() {
5+
group('BinarySearchTree', () {
6+
test('data is retained', () {
7+
final bst = new BinarySearchTree('4');
8+
9+
expect(bst.root.data, equals('4'));
10+
}, skip: false);
11+
12+
group('insert data at proper node', () {
13+
test('smaller number at left node', () {
14+
final bst = new BinarySearchTree('4')..insert('2');
15+
16+
expect(bst.root.data, equals('4'));
17+
expect(bst.root.left.data, equals('2'));
18+
}, skip: true);
19+
20+
test('same number at left node', () {
21+
final bst = new BinarySearchTree('4')..insert('4');
22+
23+
expect(bst.root.data, equals('4'));
24+
expect(bst.root.left.data, equals('4'));
25+
}, skip: true);
26+
27+
test('greater number at right node', () {
28+
final bst = new BinarySearchTree('4')..insert('5');
29+
30+
expect(bst.root.data, equals('4'));
31+
expect(bst.root.right.data, equals('5'));
32+
}, skip: true);
33+
34+
test('can create complex tree', () {
35+
final bst = new BinarySearchTree('4')
36+
..insert('2')
37+
..insert("6")
38+
..insert("1")
39+
..insert("3")
40+
..insert("5")
41+
..insert("7");
42+
43+
expect(bst.root.data, equals('4'));
44+
45+
expect(bst.root.left.data, equals('2'));
46+
expect(bst.root.left.left.data, equals('1'));
47+
expect(bst.root.left.right.data, equals('3'));
48+
49+
expect(bst.root.right.data, equals('6'));
50+
expect(bst.root.right.left.data, equals('5'));
51+
expect(bst.root.right.right.data, equals('7'));
52+
}, skip: true);
53+
});
54+
55+
group('can sort data', () {
56+
test('can sort single number', () {
57+
final bst = new BinarySearchTree('2');
58+
59+
expect(bst.sortedData, equals(['2']));
60+
}, skip: true);
61+
62+
test('can sort if second number is smaller than first', () {
63+
final bst = new BinarySearchTree('2')..insert('1');
64+
65+
expect(bst.sortedData, equals(['1', '2']));
66+
}, skip: true);
67+
68+
test('can sort if second number is same as first', () {
69+
final bst = new BinarySearchTree('2')..insert('2');
70+
71+
expect(bst.sortedData, equals(['2', '2']));
72+
}, skip: true);
73+
74+
test('can sort if second number is greater than first', () {
75+
final bst = new BinarySearchTree('2')..insert('3');
76+
77+
expect(bst.sortedData, equals(['2', '3']));
78+
}, skip: true);
79+
80+
test('can sort complex tree', () {
81+
final bst = new BinarySearchTree('2')
82+
..insert("1")
83+
..insert("3")
84+
..insert("6")
85+
..insert("7")
86+
..insert("5");
87+
88+
expect(bst.sortedData, equals(['1', '2', '3', '5', '6', '7']));
89+
}, skip: true);
90+
});
91+
});
92+
}

0 commit comments

Comments
 (0)