diff --git a/config.json b/config.json index d1d4d20a38..da1dd64386 100644 --- a/config.json +++ b/config.json @@ -1200,6 +1200,20 @@ "reactive_programming" ] }, + { + "uuid": "6f196341-0ffc-9780-a7ca-1f817508247161cbcd9", + "slug": "binary-search-tree", + "core": false, + "unlocked_by": null, + "difficulty": 4, + "topics":[ + "recursion", + "classes", + "trees", + "searching", + "object_oriented_programming" + ] + }, { "uuid": "e7351e8e-d3ff-4621-b818-cd55cf05bffd", "slug": "accumulate", diff --git a/exercises/binary-search-tree/README.md b/exercises/binary-search-tree/README.md new file mode 100644 index 0000000000..cbf5c0fa56 --- /dev/null +++ b/exercises/binary-search-tree/README.md @@ -0,0 +1,71 @@ +# 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 + + +## Submitting Exercises + +Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/` directory. + +For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit /python/bob/bob.py`. + +For more detailed information about running tests, code style and linting, +please see the [help page](http://exercism.io/languages/python). + +## Source + +Wikipedia [https://en.wikipedia.org/wiki/Binary_search_tree](https://en.wikipedia.org/wiki/Binary_search_tree) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. \ No newline at end of file diff --git a/exercises/binary-search-tree/binary_search_tree.py b/exercises/binary-search-tree/binary_search_tree.py new file mode 100644 index 0000000000..db5cd44fca --- /dev/null +++ b/exercises/binary-search-tree/binary_search_tree.py @@ -0,0 +1,14 @@ +class TreeNode(object): + def __init__(self, value): + self.value = value + + +class BinarySearchTree(object): + def __init__(self): + pass + + def add(self, value): + pass + + def search(self, value): + pass diff --git a/exercises/binary-search-tree/binary_search_tree_test.py b/exercises/binary-search-tree/binary_search_tree_test.py new file mode 100644 index 0000000000..a1f2ecc3b4 --- /dev/null +++ b/exercises/binary-search-tree/binary_search_tree_test.py @@ -0,0 +1,58 @@ +import unittest + +from binary_search_tree import BinarySearchTree + + +class BinarySearchTreeTests(unittest.TestCase): + + def test_add_integer_numbers(self): + bst = BinarySearchTree() + bst.add(1) + bst.add(8) + bst.add(3) + bst.add(5) + bst.add(2) + self.assertEqual(list(bst.list()), [1, 2, 3, 5, 8]) + + def test_add_float_numbers(self): + bst = BinarySearchTree() + bst.add(7.5) + bst.add(5.3) + bst.add(5.5) + bst.add(6.0) + bst.add(7.7) + self.assertEqual(list(bst.list()), [5.3, 5.5, 6.0, 7.5, 7.7]) + + def test_add_mixed_numbers(self): + bst = BinarySearchTree() + bst.add(1) + bst.add(8) + bst.add(7.5) + bst.add(5.3) + self.assertEqual(list(bst.list()), [1, 5.3, 7.5, 8]) + + def test_add_duplicated_numbers(self): + bst = BinarySearchTree() + bst.add(1) + bst.add(1) + bst.add(7.5) + bst.add(5.3) + self.assertEqual(list(bst.list()), [1, 1, 5.3, 7.5]) + + def test_search_existent_numbers(self): + bst = BinarySearchTree() + bst.add(1) + bst.add(7.5) + self.assertEqual(bst.search(1).value, 1) + self.assertEqual(bst.search(7.5).value, 7.5) + + def test_search_nonexistent_numbers(self): + bst = BinarySearchTree() + bst.add(1) + bst.add(7.5) + self.assertIs(bst.search(6), None) + self.assertIs(bst.search(8.8), None) + + +if __name__ == '__main__': + unittest.main() diff --git a/exercises/binary-search-tree/example.py b/exercises/binary-search-tree/example.py new file mode 100644 index 0000000000..1d4a6785a2 --- /dev/null +++ b/exercises/binary-search-tree/example.py @@ -0,0 +1,61 @@ +from collections import deque + + +class TreeNode(object): + def __init__(self, value): + self.value = value + self.left_node = None + self.right_node = None + + def __str__(self): + return str(self.value) + + +class BinarySearchTree(object): + def __init__(self): + self.root = None + + def add(self, value): + if(self.root is None): + self.root = TreeNode(value) + else: + inserted = False + cur_node = self.root + + while not inserted: + if(value <= cur_node.value): + if(cur_node.left_node): + cur_node = cur_node.left_node + else: + cur_node.left_node = TreeNode(value) + inserted = True + elif(value > cur_node.value): + if(cur_node.right_node): + cur_node = cur_node.right_node + else: + cur_node.right_node = TreeNode(value) + inserted = True + + def search(self, value): + cur_node = self.root + found = False + while not found: + if(cur_node is None): + return None + elif(value < cur_node.value): + cur_node = cur_node.left_node + elif(value > cur_node.value): + cur_node = cur_node.right_node + elif(value == cur_node.value): + return cur_node + + def list(self): + elements = deque() + self.trav_inorder(self.root, elements) + return elements + + def trav_inorder(self, node, elements): + if(node is not None): + self.trav_inorder(node.left_node, elements) + elements.append(node.value) + self.trav_inorder(node.right_node, elements)