diff --git a/README.md b/README.md index e414413..275d3b0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Tree Exercise -In this exercise you will implement, in Ruby, several Tree methods. +In this exercise you will implement, in Python, several Tree methods. - `add(value)` - This method adds a key-value pair to the Binary Search Tree - `find(value)` - This method returns the matching value for the given key if it is in the tree and `None` if the key is not found in the tree. diff --git a/binary_search_tree/tree.py b/binary_search_tree/tree.py index cdd5abc..428025e 100644 --- a/binary_search_tree/tree.py +++ b/binary_search_tree/tree.py @@ -7,51 +7,155 @@ def __init__(self, key, val = None): self.value = val self.left = None self.right = None - - + class Tree: def __init__(self): self.root = None - # Time Complexity: - # Space Complexity: + # Time/ Space Complexity for unbalanced tree: O(n) + #Time/ Space Complexity for unbalanced tree: O(log n) + def add(self, key, value = None): - pass + if self.root == None: + self.root = TreeNode(key, value) + else: + self._add(self.root, key, value) + + def _add(self, current_node, key, value): + if current_node == None: + return TreeNode(key, value) - # Time Complexity: - # Space Complexity: + if key <= current_node.key: + current_node.left = self._add(current_node.left, key, value) + else: + current_node.right = self._add(current_node.right, key, value) + return current_node + + # Time Complexity: O(log n) + # Space Complexity: O(1) def find(self, key): - pass + if self.root == None: + return None + current = self.root + while current: + if current.key == key: + return current.value + elif key > current.key: + current = current.right + else: + current = current.left + return None - # Time Complexity: - # Space Complexity: + # Time Complexity: O(n) + # Space Complexity: O(n) def inorder(self): - pass + values =[] + + if self.root == None: + return values + + return self._in_order(self.root, values) - # Time Complexity: - # Space Complexity: + def _in_order(self, node, values): + if node == None: + return + + self._in_order(node.left, values) + values.append({ + 'key': node.key, + 'value': node.value + }) + self._in_order(node.right, values) + + return values + + # Time Complexity: O(n) + # Space Complexity: O(n) def preorder(self): - pass + values = [] + + if self.root == None: + return values + + return self._pre_order(self.root, values) + + def _pre_order(self, node, values): + if node == None: + return - # Time Complexity: - # Space Complexity: + values.append({ + 'key': node.key, + 'value': node.value + }) + self._pre_order(node.left, values) + self._pre_order(node.right, values) + + return values + + # Time Complexity: O(n) + # Space Complexity: O(n) def postorder(self): - pass + values = [] + + if self.root == None: + return values + + return self._post_order(self.root, values) + + def _post_order(self, node, values): + if node == None: + return + + self._post_order(node.left, values) + self._post_order(node.right, values) + values.append({ + 'key': node.key, + 'value': node.value + }) - # Time Complexity: - # Space Complexity: + return values + + # Time Complexity: O(n) + # Space Complexity: O(log n) (balanced) or O(n) for unbalanced def height(self): - pass + if self.root == None: + return 0 + + return self._height(self.root) + + def _height(self, node): + if node == None: + return 0 + l = self._height(node.left) + r = self._height(node.right) + + return (1 + max(l, r)) # # Optional Method -# # Time Complexity: -# # Space Complexity: +# # Time Complexity: O(n^2) +# # Space Complexity: O(n) +## to-do: rewrite below using dequeue or linked list for linear time + def bfs(self): - pass + values = [] + queue = [] + if self.root: + queue.append(self.root) - + while len(queue) > 0: + current_node = queue.pop(0) + if current_node.left: + queue.append(current_node.left) + if current_node.right: + queue.append(current_node.right) + + values.append({ + "key": current_node.key, + "value": current_node.value, + }) + return values # # Useful for printing