Trees Lecture - G5 - With Code
Trees Lecture - G5 - With Code
3
Real-Life Problem
What data structure will be best to implement a file management system ?
4
Real-Life Problem
What about linked-lists? Why?
6
What are Trees?
7
Definition
● A hierarchical, non-linear data structure composed of zero or more
nodes.
● Why the name tree? Such data structure branches out starting from the
root, pretty much like the trees around us but upside down.
8
Terminologies in Trees
9
Terminology - Node
● A data structure that contains a value, a condition or a data structure
(yes even trees)
● In trees, a node can have 0 or more children but at most one parent.
1 class Node:
def __init__(self, key:int):
self.left = None
2 3 self.right = None
self.val = key
4 5
10
Terminology - Parent
● A node is called parent node to the nodes it’s pointers point to.
2 3
11
Terminologies - Child, Siblings
● The nodes a node’s pointers point to are called child nodes of that node.
● Siblings: nodes that have the same parent node.
2 3
12
Terminology - Edge
● Edge: a connection between a child and parent node.
2 3
13
Terminology - Root Node
● A node with no parent is called a root node.
2 3
4 5
14
Terminology - Inner Node
● A node with the parent and the child is called an inner node or internal
node
2 3
4 5
15
Terminology - Leaf Node
● A node with no children
2 3
4 5
16
Terminology - Ancestor
● A node is called the ancestor of another node if it is the parent of the
node or the ancestor of its parent node.
● In simpler terms, A is an ancestor of B if it is B’s parent node, or the
parent of B’s parent node or the parent of the parent of B’s parent node
and so on.
1
2 3
4 5 17
Terminology - Descendant
● A node A is called the descendant of another node B if B is the ancestor
of A.
● In simpler terms, A is a descendant of B if A is the child node of B, or the
child of the child node of B or the child of child of the child node of B
and so on.
1
2 3
4 5
18
Terminology - Sub-tree
● A subtree of a tree consists of a node n and all of the descendants of node n.
1 1 1
2 3 2 3 2 3
4 5 4 5 4 5
1 1
2 3 2 3
4 5 4 5
19
Terminology - Level, Height and Depth
● The level of a tree indicates how far you are from the root
● The height of a tree indicates how far you are from the farthest leaf
● The depth of the node is the total number of edges from the root to the
current node. Level = depth + 1
21
Types of Trees
22
Types
Depending on the number of children of every node, trees are generally classified
as
1. Binary tree: Every node has at most two children
2. n-ary tree: Every node has at most n children
Binary trees 3-ary trees ( a.k.a, Ternary Trees)
1 1
2 3 6
2 3
4 5 5
4 5 23
Types - Implementation
Note: the N-ary tree implementation can be used for binary trees if
len(self.children) <= 2
24
Types - Binary Trees
A binary tree is a tree in which every internal node and root node has at most two children.
These two child nodes are often called the left child node or right child node of the node.
Binary trees
2 3
4 5
25
Types - Full Binary Trees
● A full binary tree is a special type of binary tree where each node has 0 or 2
children
Full Binary tree Not a Full Binary tree
1 1
2 3 2 3
4 5 4 5 6
10 11 8 10 11
26
Types - Complete Binary Trees
● A complete binary tree is a special type of binary tree where all the levels of
the tree are filled completely except the “lowest” level nodes which are filled
from as left as possible.
● A complete binary tree is just like a full binary tree, but with two major
differences
○ All the leaf elements must lean towards the left.
○ The last leaf element might not have a right sibling i.e. a complete binary
tree doesn't have to be a full binary tree.
27
Types - Complete Binary Trees
1 1
2 3 2 3
4 5 6 7 4 5
8 9 10 8 10 11
28
Types - Perfect Binary Trees
● A perfect binary tree is a special type of binary tree in which all the leaf nodes
are at the same depth, and all non-leaf nodes have two children.
2 3
4 5 6 7
29
Types - Balanced Binary Trees
● A balanced binary tree is defined as a binary tree in which the height of the left
and right subtree of any node differ by not more than 1.
30
Types - Balanced Binary Trees
1
1
2 3
2 3
4 5 6
4 5
10
8 10
31
Types - Binary Search Trees
● A binary search tree is a binary tree that has the following properties:
○ The left subtree of the node only contains values less than the value of the node.
○ The right subtree of the node only contains values greater than or equal to the value of
the node.
○ The left and right subtrees of the nodes should also be the binary search trees.
4 4
2 6 2 6
1 3 7 7
1 3
32
Types - Binary Search Trees
● Why binary search trees? Efficient search, insert and delete.
● Applications
○ Sorting large datasets
○ Maintaining sorted stream
○ Implementing dictionaries and priority queues
33
Tree Traversal
34
Tree Traversal
● Traversing a tree means visiting every value. Why would you need to do that?
35
Tree Traversal - Depth First Search
● Depth-first search (DFS) is a method for exploring a tree or graph.
● In a DFS, you go as deep as possible down one path before backing up and
trying a different one. You explore one path, hit a dead end, and go back and
try a different one.
● There are basically three ways of traversing a binary tree:
1. Preorder Traversal
2. Inorder Traversal
3. Postorder Traversal
36
Depth First Search - Preorder
● In preorder traversal, we recursively traverse the parent node first, then the left
subtree of the node, and finally, the node’s right subtree.
● Problem Link
37
Depth First Search - Preorder
if root:
preOrder(root.left)
preOrder(root.right)
38
Depth First Search - Inorder
● In inorder traversal, we traverse the left subtree first, then the the parent node
and finally, the node’s right subtree.
● Inorder traversal in BST results in a sorted order of the values
Problem Link
39
Depth First Search - Inorder
if root:
inOrder(root.left)
ans.append(root.val),
inOrder(root.right)
40
Depth First Search - Postorder
● In postorder traversal, we traverse the left subtree first, then the the right
subtree of, and finally, the parent node.
Problem Link
41
Depth First Search - Postorder
# A function to do preorder tree traversal
if root:
postOrder(root.left)
postOrder(root.right)
42
Depth First Search - Example
Preorder:
1
2 3 Inorder:
4 5 6
Postorder:
43
Depth First Search - Example
Preorder: 1 2 4 5 0 3 6
1
2 3 Inorder: 4 2 0 5 1 6 3
4 5 6
Postorder: 4 0 5 2 6 3 1
44
Checkpoint
link
45
Practice Problem
Link
46
Simulation
Given the root of a binary tree, return its maximum depth. A binary tree maximum
depth is the number of nodes along the longest path from the root node down to
the farthest leaf node.
Example 1:
3
Input: root = [3,9,20,null,null,15,7]
Output: 3
9 20 Example 2:
Input: root = [1,null,2]
Output: 2
15 7
47
Simulation - Solution
● What if the tree is empty?
Answer: max_depth = 0
48
Simulation - Solution
1 + max(max_depth(root.left), max_depth(root.right))
9 20
15 7
49
Simulation - Solution
1 + max(max_depth(root.left), max_depth(root.right))
1
9 20
15 7
50
Simulation - Solution
1 + max(1, max_depth(root.right))
9 20
15 7
51
Simulation - Solution
1 + max(1, max_depth(root.right))
1 + max(max_depth(root.left),
max_depth(root.right))
9 20
15 7
52
Simulation - Solution
1 + max(1, max_depth(root.right))
1 + max(max_depth(root.left),
max_depth(root.right))
9 20
15 7
53
Simulation - Solution
1 + max(1, max_depth(root.right))
1 + max(1,max_depth(root.right))
9 20
15 7
54
Simulation - Solution
1 + max(1, max_depth(root.right))
1 + max(1,max_depth(root.right))
9 20
15 7
55
Simulation - Solution
1 + max(1, max_depth(root.right))
1 + max(1, 1) = 2
9 20
15 7
56
Simulation - Solution
1 + max(1,2) = 3
9 20
15 7
57
Implementation - Recursive
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def maxDepth(self, root:TreeNode): Time complexity: O(n)
""" Space Complexity: O(d)
:type root: TreeNode
:rtype: int
"""
def find_max(node):
if not node : return 0
left = 1 + find_max(node.left)
right = 1 + find_max(node.right)
return max(left,right)
return find_max(root)
58
Implementation - Iterative
class Solution:
def maxDepth(self, root:TreeNode):
"""
:type root: TreeNode
:rtype: int
"""
if root is None : return 0
while stack:
node, depth = stack.pop()
if node:
res = max(res, depth)
stack.append((node.left, depth+1))
stack.append((node.right, depth+1))
return res
59
Question
Insert into a Binary
Search Tree
60
Basic Operation on Trees
61
Operation - Searching
● The algorithm depends on the property of BST that if each left subtree
has values below parent and each right subtree has values above the
parent.
● If the value is below the parent, we can say for sure that the value is
not in the right subtree; we need to only search in the left subtree
● If the value is above the parent, we can say for sure that the value is
not in the left subtree; we need to only search in the right subtree.
● Let us try to visualize this with a diagram searching for 4 in the tree:
62
Operation - Searching
8
8
3 10
1 6 14
4 7
63
Operation - Searching
8
3
3 10
8
1 6 14
4 7
64
Operation - Searching
8
6
3 10
3
1 6 14
8
4 7
65
Operation - Searching
8
4
3 10
6
1 6 14
3
8
4 7
66
Operation - Searching Algorithm
def search(root):
if root is None:
return None
if number == root.val:
return root.val
if number < root.val:
return search(root.left)
` if number > root.val:
return search(root.val)
67
Operation - Insertion
try to maintain the BST rule that the left subtree is lesser than root and the
right subtree is larger than root.
● We keep going to either right subtree or left subtree depending on the value
and when we reach a point left or right subtree is null, we put the new node
there.
68
Operation - Insertion
Insert 5 in to the BST
8
3 10
1 6
14
4 7
69
Operation - Insertion
Insert 5 in to the BST
8
3 10
1 6
14
4 7
70
Operation - Insertion
Insert 5 in to the BST
8
3 10
1 6
14
4 7
71
Operation - Insertion
Insert 5 in to the BST
8
3 10
1 6
14
4 7
72
Operation - Insertion
Insert 5 in to the BST
8
3 10
1 6
14
4 7
5
73
Operation - Insertion Algorithm
74
Practice Problem
Delete Node in a BST
75
Operation - Deletion
● There are three cases for deleting a node from a binary search tree.
Case One: In the first case, the node to be deleted is the leaf node. In such a case, simply
delete the node from the tree. 4 is to be deleted.
3 10
1 6
14
4 7
76
Operation - Deletion
8
3 10
1 6
14
4 7
77
Operation - Deletion
Case Two: In the second case, the node to be deleted lies has a single child node.
In such a case follow the steps below:
3 10
1 6
14
4 7
78
Operation - Deletion
8
3 10
1 6
14
4 7
79
Operation - Deletion
Case Three: The node to be deleted has two children. In such a case follow the steps
below:
80
Operation - Deletion
8 Inorder traversal: 1 3 4 6 7 8 10 14
3 10
1 6
14
4 7
81
Operation - Deletion
8 Inorder traversal: 1 3 4 6 7 8 10 14
3 10
1 6
14
4 7
82
Operation - Deletion
8 Inorder traversal: 1 4 6 7 8 10 14
4 10
1 6
14
3 7
83
Operation - Deletion Algorithm
def deleteNode(root, key):
# Return if the tree is empty
if not root:
return root
# Find the node to be deleted
if key < root.key:
root.left = deleteNode(root.left, key)
elif(key > root.key):
root.right = deleteNode(root.right, key)
else:
# If the node is with only one child or no child
if not root.left:
return root.right
elif not root.right:
return root.left
84
Operation - Deletion Algorithm
`# Find the inorder successor
def minValueNode(node):
current = node
return current
85
Time and Space Complexity Analysis
● Traversing ● Traversing
○ Time = ? ○ Time = ?.
● Searching ● Searching
○ Time = ? ○ Time = ?
● Insertion ● Insertion
○ Time = ? ○ Time = ?
● Deletion ● Deletion
○ Time = ? ○ Time = ?
● Space = ? ● Space = ?
86
Time and Space Complexity Analysis
n = number of nodes
h = height of the binary tree
● Traversing ● Traversing
○ Time = O(n) ○ Time = O(n).
● Searching ● Searching
○ Time = O(n) ○ Time = O(h)
● Insertion ● Insertion
○ Time = O(n) ○ Time = O(h)
● Deletion ● Deletion
○ Time = O(n) ○ Time = O(h)
88
Applications of Trees
● Representation structure in File Explorer. (Folders and Subfolders) uses N-ary Tree.
● Auto-suggestions when you google something using Trie.
● Used in decision-based machine learning algorithms.
● Tree forms the backbone of other complex data structures like heap, priority queue,
spanning tree, etc.
● A binary tree is used in database indexing to store and retrieve data in an efficient
manner.
● Binary Search Trees (BST) can be used in sorting algorithms.
89
Practice Questions
● Merge Two Binary Trees
● Search in Binary Search Trees
● Same Tree
● Lowest Common Ancestor of Binary
Search Tree
● Validate Binary Search Trees
● Binary Tree Zigzag Level Order
Traversal
● Maximum Difference Between Node
and Ancestor
● Kth smallest Element in BST
● Maximum Sum BST in Binary Tree
90
Quote of the Day
91