Skip to content

Commit

Permalink
new mds for bst folder
Browse files Browse the repository at this point in the history
  • Loading branch information
gitgik committed Feb 23, 2021
1 parent 4b8b928 commit 3821456
Show file tree
Hide file tree
Showing 9 changed files with 810 additions and 9 deletions.
179 changes: 179 additions & 0 deletions binary-search-trees/bst_construction_from_array.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
### Construct a Min Height BST
Given an sorted array of integers, construct a min-height Binary Search Tree and return the root. All the BST rules apply.

```
Sample input:
[1, 2, 3, 5, 10, 12, 15, 20, 24]
Sample output:
10
/ \
2 15
/ \ / \
1 3 12 20
\ \
5 24
```


```python
# First Approach
def bst_constructor(A):
"""Complexity
O(N log N) time where N is the total number of elements in the array
O(N) space
"""
if len(A) == 1:
return BST(A[0])

return bst_helper(A, None, 0, len(A) - 1)

def bst_helper(A, bst, start, end):
# base case
if start > end:
return
else:
mid = (start + end) // 2
value_to_add = A[mid]
if bst is None:
# create the root
bst = BST(value_to_add)
else:
bst.insert(value_to_add)
bst_helper(A, bst, start, mid - 1)
bst_helper(A, bst, mid + 1, end)
return bst

class BST:
def __init__(self, value):
self.value = value
self.left = None
self.right = None

def insert(self, value):
if value_to_add < self.value:
if self.left is None:
self.left = BST(value_to_add)
else:
self.left.insert(value_to_add)
else:
if self.right is None:
self.right = BST(value_to_add)
else:
self.right.insert(value_to_add)

```


```python
# Second approach
def bst_constructor(array):
"""O(n) time | O(n) space"""
return bst_constructor_helper(array, None, 0, len(array) - 1)

def bst_constructor_helper(array, bst, start_index, end_index):
if end_index < start_index:
return
else:
mid_index = (start_index + end_index) // 2
new_bst_node = BST(array[mid_index])
if bst is None:
bst = new_bst_node
else:
if array[mid_index] < bst.value:
bst.left = BST(array[mid_index])
bst = bst.left
else:
bst.right = BST(array[mid_index])
bst = bst.right

bst_constructor_helper(array, bst, start_index, mid_index - 1)
bst_constructor_helper(array, bst, mid_index + 1, end_index)
return bst
```


```python
# Third approach
def bst_construct(A):
"""O(n) time | O(n) space"""
return bst_construct_helper(A, 0, len(A) - 1)

def bst_construct_helper(A, start, end):
# base case
if end < start:
return None
mid = (start + end) // 2
bst = BST(A[mid])
bst.left = bst_construct_helper(A, start, mid - 1)
bst.right = bst_construct_helper(A, mid + 1, end)
return bst

```


```python
root = bst_construct([1, 2, 4])
print(f"{root.value}, {root.left.value}, {root.right.value}")
```

2, 1, 4



```python
root = bst_construct([1, 2, 3, 5, 10, 12, 15, 20, 24])
```


```python
root.left.left.value
```




1




```python
# Fourth Appraoch: Cleanest
def bstConstruct(A):
if not A:
return None
mid = len(A) // 2
root = BST(A[mid])
root.left = bstConstruct(A[:mid])
root.right = bstConstruct(A[mid+1:])
return root
```


```python
root = bstConstruct([1, 2, 3, 4, 5, 6, 7])

def inOrder(node):
if not node:
return
inOrder(node.left)
print(node.value)
inOrder(node.right)

inOrder(root)
```

1
2
3
4
5
6
7



```python

```
11 changes: 2 additions & 9 deletions binary-search-trees/bst_implementation.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -123,23 +123,16 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"10\n"
]
},
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 6,
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
Expand Down
132 changes: 132 additions & 0 deletions binary-search-trees/bst_implementation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
## BST implementation

A node is said to be a BST node if and only if it satisfies the BST property:
- its value is greater than all the node values to its left;
- its values is less than the values of every node to its right,
- and all its children nodes are either BST nodes themselves or null values.

> The BST should support insertion, searching and removal of values.
The removal method should only remove the first instance of the target value.



```python
class BST:
"""
We'll use the iterative approach (due to constant space).
Recursive approach creates a call stack in memory -> O(n) space.
"""

def __init__(self, value):
self.value = value
self.left = None
self.right = None

def insert(self, value):
"""Average Case: O(log(N)) time | O(1) space
Worst Case: (Where the tree is unbalanced
and has only one branch to the left)
O(n) time, where n = number of nodes in the tree
O(1) space
"""
current_node = self
while True:
if value < current_node.value:
if current_node.left is None:
current_node.left = BST(value)
break
else:
current_node = current_node.left
else:
# value is greater than current node's value
if current_node.right is None:
current_node.right = BST(value)
break
else:
current_node = current_node.right
return self

def contains(self, value):
"""Average Case: O(log(N)) time | O(1) space
Worst Case: O(n) time | O(1) space
"""
current_node = self
while current_node is not None:
if value < current_node.value:
current_node = current_node.left
elif value > current_node.value:
current_node = current_node.right
else:
# found it!
return True
return False

def remove(self, value, parent_node=None):
"""Average Case: O(log(N)) time | O(1) space
Worst Case: O(n) time, O(1) space
"""
current_node = self
while current_node is not None:
if value < current_node.value:
parent_node = current_node
current_node = current_node.left
elif value > current_node.value:
parent_node = current_node
current_node = current_node.right
else:
# we've found the node, time to delete it
if current_node.left is not None and current_node.right is not None:
# set current node value = smallest value of right subtree.
current_node.value = current_node.right.get_min_value()
current_node.right.remove(current_node.value, current_node)
elif parent_node is None:
# if we are removing the root node (it does not have a parent node)
if current_node.left is not None:
current_node.value = current_node.left.value
current_node.right = current_node.left.right
current_node.left = current_node.left.left
elif current_node.right is not None:
current_node.value = current_node.right.value
current_node.left = current_node.right.left
current_node.right = current_node.right.right
else:
# no child nodes exist for this BST, so do nothing
pass
elif parent_node.left == current_node:
parent_node.left = (
current_node.left if current_node.left is not None else
current_node.right)
elif parent_node.right == current_node:
parent_node.right = (
current_node.left if current_node.left is not None else
current_node.right)
break
return self

def get_min_value(self):
"""Finds the smallest value in a sub-tree."""
current_node = self
while current_node.left is not None:
current_node = current_node.left
return current_node.value
```


```python
bst = BST(10).insert(5).insert(15).insert(
7).insert(2).insert(14).insert(22)

bst.contains(22)
```




True




```python

```
53 changes: 53 additions & 0 deletions binary-search-trees/bst_traversal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
```python
"""
Given a binary tree, traverse it, adding the node values into an array,
returning the array.
Assume a BST is defined as follows:
* The left subtree of a node contains only nodes with keys < the node's key.
* The right subtree of a node contains only nodes with keys > the node's key.
* Both the left and right subtrees must also be binary search trees.
"""


def in_order_traverse(tree, array):
"""
Complexity: O(n) time, O(n) space
NOTE: If we were not storing any array, the space complexity = O(d)
where d=depth of the longest branch in the BST.
"""
if tree is not None:
in_order_traverse(tree.left, array)
array.append(tree.value)
in_order_traverse(tree.right, array)
return array


def pre_order_traverse(tree, array):
"""
Complexity: O(n) time, O(n) space.
"""
if tree is not None:
array.append(tree.value)
pre_order_traverse(tree.left, array)
pre_order_traverse(tree.right, array)
return array


def post_order_traverse(tree, array):
"""
Complexity: O(n) time, O(n) space"""
if tree is not None:
post_order_traverse(tree.left, array)
post_order_traverse(tree.right, array)
array.append(tree.value)
return array

```


```python

```
Loading

0 comments on commit 3821456

Please sign in to comment.