Tree & Graph



Tree



What is tree?
A tree data structure can be defined recursively (locally) as a collection of nodes (starting at a root node), where each node is a data structure consisting of a value, together with a list of references to nodes (the "children"), with the constraints that no reference is duplicated, and none points to the root.



What is tree?
A tree data structure can be defined recursively (locally) as a collection of nodes (starting at a root node), where each node is a data structure consisting of a value, together with a list of references to nodes (the "children"), with the constraints that no reference is duplicated, and none points to the root.



A data structure made up of nodes or vertices and directed edges without having any cycle.



Types of Tree
Tree
B Tree
Trie Tree
Binary Tree
BST
RB Tree
AVL



When to Use Tree
- Simulating a hierarchical tree structure
- File System, HTML, Compiler Pattern Recognition, etc.
- Simulating search space for solutions
- DFS, BFS, Decision Tree, etc.
- Performance Improvement
- Red Black Tree, AVL, B/B+ Tree, etc.



Terminologies
- Node
- Root, Leaf (external node)
- Relations
- Parent, Child
- Siblings
- Ancestor, Descendant
- Subtree
A
B
C
D
E
F
G
J
I
H



Terminologies
- Edge (N - 1)
- Path
- Height
- Depth
- Level
A
B
C
D
E
F
G
J
I
H




Node
The depth of a node is the number of edges from the node to the tree's root node.
A root node will have a depth of 0.
The height of a node is the number of edges on the longest path from the node to a leaf.
A leaf node will have a height of 0.
Tree
The height of a tree would be the height of its root node,
or equivalently, the depth of its deepest node.
Note that depth doesn't make sense for a tree.
what is the max number of nodes a tree can have if the height of the tree is h?



Binary Tree
- Each node has at most two children.
- left child, right child.
- left subtree, right subtree



Types of Binary Tree
- Complete Binary Tree
- In which every level, except possibly the last, is completely filled, and all nodes are as far left as possible.
- High Performance
- Full Binary Tree
- Perfect Binary Tree



Properties of Binary Tree
- At Level i, at most 2^i nodes
- A tree with height k, at most ceil(2^(k+1))-1 nodes
- Complete binary tree
- With n nodes, the height will be
- number nodes from the root, then for node k, its children would be 2*k+1 and 2*k + 2



Binary Tree in Code
class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val_) {
val = val_;
left = null;
right = null;
}
}


Binary Tree in Code
class Solution {
// Please implement this function.
public void function(TreeNode root);
}


Traversal of a Binary Tree
Traversal is the basic operation for almost all binary tree problems.
-
Breadth First Search
- LevelOrder
- Depth First Search
- PreOrder, InOrder, PostOrder
- BFS: search level by level (increasing distance).
- DFS: search as far as possible for one direction.



Traversal of a Binary Tree
Traversal is the basic operation for almost all binary tree problems.
-
Breadth First Search
- LevelOrder
- Depth First Search
- PreOrder, InOrder, PostOrder
Parent Node



BFS of a Binary Tree
A
B
D
E
H
I
J
G
F
C
LevelOrder: A B C D E F G H I J



DFS of a Binary Tree
A
B
D
E
H
I
J
G
F
C
PreOrder: A B D E H I C F G J
InOrder: D B H E I A F C G J
PostOrder: D H I E B F J G C A



How to traverse (DFS)?
Tree is a recursive data structure.
- It's natural and straightforward to use recursion on such data structures (like LinkedList)
public void traverse(ListNode head) {
visit(head);
traverse(head.next);
}public void traverse(TreeNode root) {
visit(root);
traverse(root.left);
traverse(root.right);
}


PreOrder Traversal
public void preorder(TreeNode root) {
if(root != null) {
// Visit the node by printing the node data
System.out.printf("%d ",root.val);
preorder(root.left);
preorder(root.right);
}
} 


InOrder Traversal
public void inorder(TreeNode root) {
if(root != null) {
inorder(root.left);
System.out.printf("%d ",root.val);
inorder(root.right);
}
}


PostOrder Traversal
public void postorder(TreeNode root) {
if(root != null) {
postorder(root.left);
postorder(root.right);
System.out.printf("%d ",root.val);
}
}


How to traverse (BFS)?
We can't visit each node once we meet them. Need to store some node for future visit.
- Queue will be needed to keep the order



LevelOrder Traversal
public void levelorder(TreeNode root) { // BFS
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode top = queue.pop();
System.out.printf("%d ", top.val);
if (top.left != null) {
queue.offer(top.left);
}
if (top.right != null) {
queue.offer(top.right);
}
}
return;
} 


LevelOrder Traversal
public void levelorder(TreeNode root) { // BFS
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int level = 0;
while (!queue.isEmpty()) {
System.out.printf("Level %d\n", level++);
Queue<TreeNode> queue2 = new LinkedList<>();
while (!queue.isEmpty()) {
TreeNode top = queue.poll();
System.out.printf("%d ", top.val);
if (top.left != null) queue2.offer(top.left);
if (top.right != null) queue2.offer(top.right);
}
queue = queue2;
}
} 


LevelOrder Traversal
public void levelorder(TreeNode root) { // BFS
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
queue.offer(null);
int level = 0;
while (!queue.isEmpty()) {
TreeNode top = queue.poll();
if (top == null) {
System.out.printf("----Level %d\n", level++);
queue.offer(null);
} else {
System.out.printf("%d ", top.val);
if (top.left != null) queue.offer(top.left);
if (top.right != null) queue.offer(top.right);
}
}
} 


LevelOrder Traversal
public void levelorder(TreeNode root) { // BFS
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int level = 0;
int curLevelNum = 1;
while (!queue.isEmpty()) {
System.out.printf("Level %d\n", level++);
int nextLevelNum = 0;
while (curLevelNum-- != 0) {
TreeNode top = queue.poll();
System.out.printf("%d ", top.val);
if (top.left != null) {
queue.offer(top.left);
nextLevelNum++;
}
if (top.right != null) {
queue.offer(top.right);
nextLevelNum++;
}
}
curLevelNum = nextLevelNum;
}
} 


Maximum Depth of Binary Tree
Given a binary tree, find its maximum depth.
The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.



Maximum Depth of Binary Tree
Given a binary tree, find its maximum depth.
The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
public int maxDepth(TreeNode root) {
if (root == null) return 0;
int leftDepth = maxDepth(root.left);
int rightDepth = maxDepth(root.right);
return Math.max(leftDepth, rightDepth) + 1;
}


Maximum Depth of Binary Tree
Given a binary tree, find its maximum depth.
The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
public int maxDepth(TreeNode root) {
if (root == null) return 0;
return Math.max(maxDepth(root.left),
maxDepth(root.right)) + 1;
}


Minimum Depth of Binary Tree
Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.



Minimum Depth of Binary Tree
Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
public int minDepth(TreeNode root) {
if (root == null) return 0;
int leftDepth = minDepth(root.left);
int rightDepth = minDepth(root.right);
return Math.min(leftDepth, rightDepth) + 1;
}Wrong Answer



Minimum Depth of Binary Tree
Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
public int minDepth(TreeNode root) {
if (root == null) return 0;
int leftDepth = minDepth(root.left);
int rightDepth = minDepth(root.right);
return Math.min(leftDepth, rightDepth) + 1;
}Wrong Answer
A
B
C



Minimum Depth of Binary Tree
Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
public int minDepth(TreeNode root) {
if (root == null) {
return 0;
}
if (root.left == null && root.right == null) {
return 1;
}
if (root.left == null && root.right != null) {
return minDepth(root.right) + 1;
}
if (root.left != null && root.right == null) {
return minDepth(root.left) + 1;
}
return Math.min(minDepth(root.left),
minDepth(root.right)) + 1;
}A
B
C



Minimum Depth of Binary Tree
Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
public int minDepth(TreeNode root) {
if (root == null) {
return 0;
}
int leftDepth = minDepth(root.left);
int rightDepth = minDepth(root.right);
if (leftDepth == 0) {
return rightDepth + 1;
} else if (rightDepth == 0) {
return leftDepth + 1;
}
return Math.min(leftDepth, rightDepth) + 1;
}A
B
C



Minimum Depth of Binary Tree
public int minDepth(TreeNode root) {
if (root == null) return 0;
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
int minDepth = 1;
while (!queue.isEmpty()) {
Queue<TreeNode> queue2 = new LinkedList<TreeNode>();
while (!queue.isEmpty()) {
TreeNode top = queue.poll();
if (top.left == null && top.right == null) {
return minDepth;
}
if (top.left != null) {
queue2.offer(top.left);
}
if (top.right != null) {
queue2.offer(top.right);
}
}
minDepth++;
queue = queue2;
}
return minDepth;
}


Same Tree
Given two binary trees, write a function to check if they are equal or not.
Two binary trees are considered equal if they are structurally identical and the nodes have the same value.



Same Tree
Given two binary trees, write a function to check if they are equal or not.
Two binary trees are considered equal if they are structurally identical and the nodes have the same value.
- Base case: one of the roots is null.
-
Recursion rules for isSame(root1, root2)
- root1.val = root2.val
- isSame(root1.left, root2.left)
- isSame(root1.right, root2.right)



Same Tree
Given two binary trees, write a function to check if they are equal or not.
Two binary trees are considered equal if they are structurally identical and the nodes have the same value.
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null) {
return true;
} else if (p == null || q == null) {
return false;
}
return p.val == q.val
&& isSameTree(p.left, q.left)
&& isSameTree(p.right, q.right);
}


Symmetric Tree
Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).
1 / \ 2 2 / \ / \ 3 4 4 3
1 / \ 2 2 / \ / \ 4 3 4 3
1 / \ 2 2 \ \ 3 3
1 / \ 2 2 / \ 3 3
True
False
False
True



Symmetric Tree
Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).
1 / \ 2 2 \ \ 3 3
1 / \ 2 2 / \ 3 3
False
True
Root is Symmetric
- root.left is symmetric to root.right
A is symmetric to B
- A.val == B.val
- A.left is symmetric to B.right
- A.right is symmetric to B.left



Symmetric Tree
public boolean isSymmetric(TreeNode root) {
if (root == null) {
return true;
}
return isSymmetric(root.left, root.right);
}
public boolean isSymmetric(TreeNode left, TreeNode right) {
if (left == null && right == null) {
return true;
}
if (left == null || right == null) {
return false;
}
return left.val == right.val
&& isSymmetric(left.left, right.right)
&& isSymmetric(left.right, right.left);
}


Path Sum
Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
Sum: 22 --> True
(5 - 4 - 11 - 2)



Path Sum
Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
- Except picking from all of numbers, only path from root to leaf is acceptable.
-
hasSum(TreeNode root, int sum)
- Base case: root is leaf.
- hasSum(root, sum) = hasSum(root.left, sum-root.val) || hasSum(root.right, sum-root.val)



Path Sum
Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
public boolean hasPathSum(TreeNode root, int sum) {
if (root == null) {
return false;
}
if (root.left == null && root.right == null) {
if (sum == root.val) {
return true;
}
return false;
}
return hasPathSum(root.left, sum - root.val) ||
hasPathSum(root.right, sum - root.val);
}


Path Sum II
Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum.



public List<List<Integer>> pathSum(TreeNode root, int sum) {
List<List<Integer>> results = new ArrayList<>();
pathSum(results, new ArrayList<Integer>(), root, sum);
return results;
}
private void pathSum(List<List<Integer>> results,
List<Integer> path, TreeNode root, int sum){
if (root == null) {
return;
}
sum -= root.val;
if (root.left == null && root.right == null) {
if (sum == 0){
path.add(root.val);
results.add(new ArrayList<Integer>(path));
path.remove(path.size() - 1);
}
return;
}
path.add(root.val);
pathSum(results, path, root.left, sum);
pathSum(results, path, root.right, sum);
path.remove(path.size() - 1);
}


30
18
13
24
22
27
47
40
31
34
Binary Search Tree



Binary Search Tree
- All subtrees are BST
- All elements in left sub-tree is small than root
- All elements in Right sub-tree is larger than root
- If we do InOrder traversal, the result of BST is a sorted array



Binary Search Tree
- Find
- Add
- Remove



30
18
13
24
22
27
47
40
31
34
Binary Search Tree - Find
- 24: 30 -> 18 -> 24 -> true
- 42: 30 -> 34 -> 40 -> 47 -> false



public boolean find(int value, TreeNode root) {
TreeNode cur = root;
while(cur != null) {
if (val == cur.value) {
return true;
}
if (value < cur.val) {
cur = cur.leftNode;
} else {
cur = cur.rightNode;
}
}
return false;
}Binary Search Tree - Find
O(logN)



30
18
13
24
22
27
47
40
31
34
Binary Search Tree - Add
- Add 42
- 30 -> 34 -> 40 -> 47, doesn't exist.
- Add 42 to 47's left.



30
18
13
24
22
27
47
40
31
34
Binary Search Tree - Add
- Add 42
- 30 -> 34 -> 40 -> 47, doesn't exist.
- Add 42 to 47's left.
42



Binary Search Tree - Add
public boolean add(int value, TreeNode root) {
if (root == null) {
root = new TreeNode(value);
return true;
}
TreeNode cur = root;
while (cur != null) {
if (cur.val == value) {
return false;
}
if (value < cur.val) {
if (cur.leftNode != null) {
cur = cur.leftNode;
} else {
cur.leftNode = new TreeNode(value);
return true;
}
} else {
if (cur.rightNode != null) {
cur = node.rightNode;
} else {
cur.rightNode = new TreeNode(value);
return true;
}
}
}
return false;
}O(logN)



30
18
13
24
22
27
47
40
31
34
Binary Search Tree - Remove
- Remove 27
- 30 -> 18 -> 24 -> 27, exist,
- Remove
- Remove 30 ?
42



Binary Search Tree - Remove
- Remove one TreeNode Q
- If the node Q is a leaf
- If the node Q has one child R
- the child is left child
- the child is right child
- If the node Q has two children R1, R2



P
Q
R
P
Q
R
P
Q
R
P
Q
R
P<R<Q
P<Q<R
R<Q<P
Q<R<P
Just use R to replace Q
Binary Search Tree - Remove



P
Q
R1
R2
If we remove Q, which is the best substitute?
Binary Search Tree - Remove



P
Q
R1
R2
If we remove Q, which is the best substitute?
- The one before Q and after Q in InOrder Traversal.
Binary Search Tree - Remove



public static boolean remove(int value, Node root) {
if(root == null) return false;
if(root.data == value) {
root = removeNode(root);
return true;
}
Node node = root;
while(node != null) {
if(node.data > value) {
if(node.leftNode != null && node.leftNode.data != value) {
node = node.leftNode;
}
else if(node.leftNode == null) return false;
else {
node.leftNode = removeNode(node.leftNode);
return true;
}
}
else if(node.data < value) {
if(node.rightNode != null && node.rightNode.data != value) {
node = node.rightNode;
}
else if(node.rightNode == null) return false;
else {
node.rightNode = removeNode(node.rightNode);
return true;
}
}
else return false;
}
return false;
}


public static Node removeNode(Node node) {
if(node.leftNode == null && node.rightNode == null) {
return null;
}
else if(node.leftNode == null) {
return node.rightNode;
}
else if(node.rightNode == null) {
return node.leftNode;
}
else {
node.data = findAndRemove(node);
return node;
}
}
public static int findAndRemove(Node node) {
int result;
if(node.leftNode.rightNode == null) {
result = node.leftNode.data;
node.leftNode = node.leftNode.leftNode;
return result;
}
node = node.leftNode;
while(node.rightNode.rightNode != null) {
node = node.rightNode;
}
result = node.rightNode.data;
node.rightNode = node.rightNode.leftNode;
return result;
}


30
18
13
24
22
27
47
40
31
34
42
43
30
18
13
24
22
27
47
43
34
40
42
31
Binary Search Tree (*)



We know the search time is highly related to the height of the tree. If we keep add and remove elements in the tree, the tree will become unbalanced.
So we have Red-black tree and AVL tree, they could use rotation and reconstruct to make the tree balance.
Binary Search Tree (*)



Types of Tree
Tree
B Tree
Trie Tree
Binary Tree
BST
RB Tree
AVL



Graph



What is graph?
A graph data structure consists of a finite (and possibly mutable) set of vertices or nodes or points, together with a set of unordered pairs of these vertices for an undirected graph or a set of ordered pairs for a directed graph.
These pairs are known as edges, arcs, or lines for an undirected graph and as arrows, directed edges, directed arcs, or directed lines for a directed graph.



Types of Graph
- Undirected graph
- Directed graph



Types of Graph
- Directed graph
- Directed Acylic Graph



Types of Graph
- Directed graph
- Directed Acylic Graph
- DFS
- Topological Sort
- Directed Acylic Graph



Graph Representation
- GraphNode
- There is no root in the graph
- Need multiple nodes to represent a graph
class GraphNode {
int val;
List<GraphNode> neighbors;
}



Graph Representation
- Adjacent matrices
- |V| vertices, then |V|*|V| matrix of 0s and 1s for the graph.
| 1 | 1 | 1 | ||
|---|---|---|---|---|
| 1 | 1 | |||
| 1 | 1 | |||
| 1 | ||||
| 1 | 1 |



Graph Representation
-
Adjacent lists
- |V| vertices, then |V| arraylist, each containing the adjacent vertices.
- 2|E| space for undirected, and |E| space for directed.
| 1 | 2 | 3 | 5 |
|---|
| 2 | 4 |
|---|
| 3 | 5 | 6 | 7 | 8 |
|---|
0:
1:
2:



Graph Traversal
- DFS, BFS
- Similar to Tree Traversal
- There could be cycles in graph, so need to mark nodes visited after visiting. Different from tree here.
- 3 states: not visited, visiting, visited



Homework (Optional)



基础班 10 Tree & Graph
By ZhiTongGuiGu
基础班 10 Tree & Graph
Tree, Charlie
- 387