Skip to content

Binary search tree updates #187

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

Merged
merged 2 commits into from
Apr 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,24 @@
"loops",
"math"
]
},
{
"slug": "binary-search-tree",
"uuid": "597f86bc-6717-4a4c-a2c6-58241ac3d6cb",
"core": true,
"unlocked_by": null,
"difficulty": 5,
"topics": [
"algorithms",
"classes",
"generics",
"inheritance",
"logic",
"object_oriented_programming",
"searching",
"sorting",
"trees"
]
}
]
}
62 changes: 62 additions & 0 deletions exercises/binary-search-tree/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Binary Search Tree

Insert and search for numbers in a binary tree.

When we need to represent sorted data, an array does not make a good
data structure.

Say we have the array `[1, 3, 4, 5]`, and we add 2 to it so it becomes
`[1, 3, 4, 5, 2]` now we must sort the entire array again! 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. But this still requires us to shift many elements down by one.

Binary Search Trees, however, can operate on sorted data much more
efficiently.

A binary search tree consists of a series of connected nodes. Each node
contains a piece of data (e.g. the number 3), a variable named `left`,
and a variable named `right`. The `left` and `right` variables point at
`nil`, or other nodes. Since these other nodes in turn have other nodes
beneath them, we say that the left and right variables are pointing at
subtrees. 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.

For example, if we had a node containing the data 4, and we added the
data 2, our tree would look like this:

4
/
2

If we then added 6, it would look like this:

4
/ \
2 6

If we then added 3, it would look like this

4
/ \
2 6
\
3

And if we then added 1, 5, and 7, it would look like this

4
/ \
/ \
2 6
/ \ / \
1 3 5 7

## Resources

- [Data structures: Binary Search Tree (YouTube)](https://youtu.be/pYT9F8_LFTM?t=9m39s)

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.
18 changes: 18 additions & 0 deletions exercises/binary-search-tree/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
errors:
unused_element: error
unused_import: error
unused_local_variable: error
dead_code: error

linter:
rules:
# Error Rules
- avoid_relative_lib_imports
- avoid_types_as_parameter_names
- literal_only_boolean_expressions
- no_adjacent_strings_in_list
- valid_regexps
3 changes: 3 additions & 0 deletions exercises/binary-search-tree/lib/binary_search_tree.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class BinarySearchTree {
// Put your code here
}
61 changes: 61 additions & 0 deletions exercises/binary-search-tree/lib/example.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
class BinarySearchTree<T extends Comparable<T>> {
/// Root node for the tree.
final Node<T> root;

BinarySearchTree(T rootData) : root = new Node<T>(rootData) {
// Note: [assert] does not run in release mode
assert(rootData != null);
}

/// Returns an empty `List` if [root] is `null`.
///
/// Otherwise returns data traversed in ascending order.
Iterable<T> get sortedData sync* {
for (var t in root?.ascendingOrder ?? <T>[]) yield t;
}

/// Returns `true` on success, `false` on failure.
bool insert(T value) => root?.insert(value) ?? false;
}

class Node<T extends Comparable<T>> {
/// The actual Data this node holds which should be a [Comparable]
final T data;

/// Left node of this node, can be `null`
Node<T> left;

/// Right node of this node, can be `null`
Node<T> right;

Node(this.data, [this.left, this.right]) {
// Note: [assert] does not run in release mode
assert(data != null);
}

/// This is **inorder** traversal of the tree.
Iterable<T> get ascendingOrder sync* {
if (data == null) return;

/// Traverse left sub-tree if it's present
for (var t in left?.ascendingOrder ?? <T>[]) yield t;

yield data;

/// Traverse right sub-tree if it's present
for (var t in right?.ascendingOrder ?? <T>[]) yield t;
}

/// Returns `true` on success, `false` on failure.
bool insert(T value) {
if (value == null) return false;

/// Insert in left sub-tree if its a smaller or equal number.
if (value.compareTo(data) <= 0) {
return left?.insert(value) ?? (left = new Node(value)).data == value;
}

/// Insert in right sub-tree if its a greater number.
return right?.insert(value) ?? (right = new Node(value)).data == value;
}
}
5 changes: 5 additions & 0 deletions exercises/binary-search-tree/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: 'binary_search_tree'
environment:
sdk: '>=1.24.0 <3.0.0'
dev_dependencies:
test: '<2.0.0'
87 changes: 87 additions & 0 deletions exercises/binary-search-tree/test/binary_search_tree_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import 'package:binary_search_tree/binary_search_tree.dart';
import 'package:test/test.dart';

void main() {
group('BinarySearchTree', () {
test('data is retained', () {
final bst = new BinarySearchTree('4');

expect(bst.root.data, equals('4'));
}, skip: false);

group('insert data at proper node', () {
test('smaller number at left node', () {
final bst = new BinarySearchTree('4')..insert('2');

expect(bst.root.data, equals('4'));
expect(bst.root.left.data, equals('2'));
}, skip: true);

test('same number at left node', () {
final bst = new BinarySearchTree('4')..insert('4');

expect(bst.root.data, equals('4'));
expect(bst.root.left.data, equals('4'));
}, skip: true);

test('greater number at right node', () {
final bst = new BinarySearchTree('4')..insert('5');

expect(bst.root.data, equals('4'));
expect(bst.root.right.data, equals('5'));
}, skip: true);

test('can create complex tree', () {
final bst = new BinarySearchTree('4')
..insert('2')
..insert("6")
..insert("1")
..insert("3")
..insert("5")
..insert("7");

expect(bst.root.data, equals('4'));

expect(bst.root.left.data, equals('2'));
expect(bst.root.left.left.data, equals('1'));
expect(bst.root.left.right.data, equals('3'));

expect(bst.root.right.data, equals('6'));
expect(bst.root.right.left.data, equals('5'));
expect(bst.root.right.right.data, equals('7'));
}, skip: true);
});

group('can sort data', () {
test('can sort single number', () {
final bst = new BinarySearchTree('2');

expect(bst.sortedData, equals(['2']));
}, skip: true);

test('can sort if second number is smaller than first', () {
final bst = new BinarySearchTree('2')..insert('1');

expect(bst.sortedData, equals(['1', '2']));
}, skip: true);

test('can sort if second number is same as first', () {
final bst = new BinarySearchTree('2')..insert('2');

expect(bst.sortedData, equals(['2', '2']));
}, skip: true);

test('can sort if second number is greater than first', () {
final bst = new BinarySearchTree('2')..insert('3');

expect(bst.sortedData, equals(['2', '3']));
}, skip: true);

test('can sort complex tree', () {
final bst = new BinarySearchTree('2')..insert("1")..insert("3")..insert("6")..insert("7")..insert("5");

expect(bst.sortedData, equals(['1', '2', '3', '5', '6', '7']));
}, skip: true);
});
});
}