diff --git a/trees/README.md b/trees/README.md
index 5a68dae..2eefb81 100644
--- a/trees/README.md
+++ b/trees/README.md
@@ -2,11 +2,11 @@
-* a node is called **leaf** if it has no children.
-* **binary trees**: each node has up to 2 children.
-* **binary search tree**: all nodes on the left are smaller than the root, which is smaller than all nodes on the right.
- * if the bst is **balanced**, it guarantees O(log(n)) for insert and search.
-* common types of balanced trees: **red-black** and **avl**.
+### binary trees
+
+
+
+* **binary trees** are trees that have each up to 2 children. a node is called **leaf** if it has no children.
* a **complete tree** is a tree on which every level is fully filled (except perhaps for the last).
* a **full binary tree** has each node with either zero or two children (and no node has only one child).
* a **perfect tree** is both full and complete (it must have exactly 2**k - 1 nodes, where k is the number of levels).
@@ -14,13 +14,83 @@
----
+----
-### breath-first search
+### binary search trees
-- iterative solutions use a queue for traversal or find the shortest path from the root node to the target node (level order problem)
+* **binary search tree** are binary trees where all nodes on the left are smaller than the root, which is smaller than all nodes on the right.
+* if a bst is **balanced**, it guarantees `O(log(N))` for insert and search. common types of balanced trees: **red-black** and **avl**.
+
+
+
+
+#### checking if valid
+
+
+
+```python
+
+def is_valid_bst_recursive(root):
+
+ def is_valid(root, min_val=float(-inf), max_val=float(inf)):
+ if root is None:
+ return True
+
+ return (min_val < root.val < max_val) and \
+ is_valid(root.left, min_val, root.val) and \
+ is_valid(root.right, root.val, max_val)
+
+ return is_valid(root)
+
+
+def is_valid_bst_iterative(root):
+
+ queue = deque()
+ queue.append((root, float(-inf), float(inf)))
+
+ while queue:
+ node, min_val, max_val = queue.popleft()
+ if node:
+ if min_val >= node.val or node.val >= max_val:
+ return False
+ if node.left:
+ queue.append((node.left, min_val, node.val))
+ if node.right:
+ queue.append((node.right, node.val, max_val))
+
+ return True
+
+
+def is_valid_bst_inorder(root):
+
+ def inorder(node):
+ if node is None:
+ return True
+
+ inorder(node.left)
+ queue.append(node.val)
+ inorder(node.right)
+
+ queue = []
+ inorder(root)
+ for i in range(1, len(queue)):
+ if queue[i] <= queue[i-1]:
+ return False
+
+ return True
+```
+
+
+
+---
+
+### breath-first search (level-order)
+
+
+
+- iterative solutions use a queue for traversal or find the shortest path from the root node to the target node:
- in the first round, we process the root node, in the second round, we process the nodes next to the root node, in the third round, we process the nodes which are two steps from the root node, etc. newly-added nodes will not be traversed immediately but will be processed in the next round.
- if node X is added to the kth round queue, the shortest path between the root node and X is exactly k.
- the processing order of the nodes in the exact same order as how they were added to the queue, which is FIFO.
@@ -74,9 +144,14 @@ def dfs(root, visited):
+---
+
#### in-order
-- left -> node -> right
+
+
+- `left -> node -> right`
+- in a bst, in-order traversal will be in ascending order (therefore, it's the most frequent used method).
```python
def inorder(self, root):
@@ -87,132 +162,47 @@ def inorder(self, root):
+---
+
#### pre-order
-- node -> left -> right
+
+
+- `node -> left -> right`
+- top-down (parameters are passed down to children), so deserialize with a queue.
+
+
```python
def preorder(self, root):
if root is None:
return []
return [root.val] + preorder(root.left) + preorder(root.right)
-````
-
-- top-down (parameters are passed down to children), so deserialize with a queue.
-
-
-
-
-#### post-order
-
-- left -> right -> node
-
-```python
-def postorder(self, root):
- if root is None:
- return []
- return postorder(root.left) + postorder(root.right) + [root.val]
-````
-
-- bottom-up solution (if you know the answer of the children, can you concatenate the answer of the nodes?):
-- deletion process is always post-order: when you delete a node, you will delete its left child and its right child before you delete the node itself.
-- also, post-order is used in mathematical expressions as it's easier to write a program to parse a post-order expression. using a stack, each time when you meet a operator, you can just pop 2 elements from the stack, calculate the result and push the result back into the stack.
+```
---
-
-### some examples in this dir
+#### post-order
-#### `Tree.py`
+- `left -> right -> node`
+- bottom-up solution (if you know the answer of the children, can you concatenate the answer of the nodes?):
+- deletion process is always post-order: when you delete a node, you will delete its left child and its right child before you delete the node itself.
+- also, post-order is used in mathematical expressions as it's easier to write a program to parse a post-order expression. using a stack, each time when you meet a operator, you can just pop 2 elements from the stack, calculate the result and push the result back into the stack.
```python
-> python3 Trees.py
-
-
-🌴🌴🌴 Testing SimpleTree 🌴🌴🌴
-a
- b
- d
- e
- c
- h
- g
-
-
-
-🌳🌳🌳 Testing BinaryTree 🌳🌳🌳
-
-🟡 Adding [4, 1, 4, 6, 7, 9, 10, 5, 11, 5] to the tree...
-🟢 Printing the tree in preorder...
-4
-1
-6
-9
-5
-5
-11
-10
-7
-4
-
-🟢 Searching for node 5: True
-❌ Searching for node 15: False
-❌ Is root a leaf? False
-🟢 Is root full? True
-❌ Is the tree balanced? False
-❌ Is the tree a binary search tree? False
-
-
-🎄🎄🎄 Testing BinarySearchTree 🎄🎄🎄
-
-🟡 Adding [4, 1, 4, 6, 7, 9, 10, 5, 11, 5] to the tree...
-❌ Item 4 not added as BSTs do not support repetition.
-❌ Item 5 not added as BSTs do not support repetition.
-🟢 Printing the tree in preorder:
-4
-1
-6
-5
-7
-9
-10
-11
-
-🟢 Searching for node 5: True
-❌ Searching for node 15: False
-❌ Is root a leaf? False
-🟢 Is root full? True
-🟢 Largest node? 11
-🟢 Smallest node? 1
-❌ Is the tree balanced? False
-🟢 Is the tree a binary search tree? True
+def postorder(self, root):
+ if root is None:
+ return []
+ return postorder(root.left) + postorder(root.right) + [root.val]
```
-
-### `BinaryTree.py`
-
-* a clean implementation adapted from the class above.
-
-```python
-> python3 BinaryTree.py
-
-🌳🌳🌳 Testing BinaryTree 🌳🌳🌳
-
-🟡 Adding [4, 1, 4, 6, 7, 9, 10, 5, 11, 5] to the tree...
-🟢 Print the tree preorder: [4, 1, 6, 9, 5, 5, 11, 10, 7, 4]
-🟢 Print the tree inorder: [4, 1, 6, 9, 5, 5, 11, 10, 7, 4]
-🟢 Print the tree postorder: [4, 1, 6, 9, 5, 5, 11, 10, 7, 4]
-
-🟢 Search for node 5: True
-❌ Search for node 15: False
-```