Copyright © 直通硅谷
http://www.zhitongguigu.com
Copyright © 直通硅谷
http://www.zhitongguigu.com
Copyright © 直通硅谷
http://www.zhitongguigu.com
A tree is a data structure made up of nodes or vertices and edges without having any cycle.
Copyright © 直通硅谷
http://www.zhitongguigu.com
Tree is one of the most important data structure in algorithms
Like our current File System
Tree has many different types
Copyright © 直通硅谷
http://www.zhitongguigu.com
Tree
B Tree
Trie Tree
Binary Tree
BST
RB Tree
AVL
Copyright © 直通硅谷
http://www.zhitongguigu.com
A
B
C
D
E
F
G
J
I
H
Copyright © 直通硅谷
http://www.zhitongguigu.com
for 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.
for 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.
The diameter (or width) of a tree is the number of nodes on the longest path between any two leaf nodes. The this tree has a diameter of 6 nodes.
what is the max number of nodes a tree can have if the height of the tree is h?
Copyright © 直通硅谷
http://www.zhitongguigu.com
Copyright © 直通硅谷
http://www.zhitongguigu.com
Copyright © 直通硅谷
http://www.zhitongguigu.com
Full [Binary] Tree
Heap is a complete [binary] tree
Copyright © 直通硅谷
http://www.zhitongguigu.com
Misuse of height
Copyright © 直通硅谷
http://www.zhitongguigu.com
public class BinaryTree<T> {
private Node<T> root;
public Tree(T rootData) {
root = new Node<T>();
root.data = rootData;
}
public static class Node<T> {
private T data;
private Node<T> leftNode;
private Node<T> rightNode;
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com
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
Copyright © 直通硅谷
http://www.zhitongguigu.com
Copyright © 直通硅谷
http://www.zhitongguigu.com
We need to use recursion to traverse a tree
public void preorder(TreeNode root) {
if(root != null) {
//Visit the node by Printing the node data
System.out.printf("%d ",root.data);
preorder(root.left);
preorder(root.right);
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com
public void inorder(TreeNode root) {
if(root != null) {
inorder(root.left);
System.out.printf("%d ",root.data);
inorder(root.right);
}
}
public void postorder(TreeNode root) {
if(root != null) {
postorder(root.left);
postorder(root.right);
System.out.printf("%d ",root.data);
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com
Can we use Stack to traverse the tree without recursion?
Copyright © 直通硅谷
http://www.zhitongguigu.com
PreOrder: visit, push left, push right?
PreOrder: visit, push right, push left
Because we need to visit left first
Copyright © 直通硅谷
http://www.zhitongguigu.com
public static void PreOrder(Node root) {
Stack<Node> nodeStack = new Stack<Node>();
nodeStack.push(root);
while(!nodeStack.empty()) {
Node node = nodeStack.pop();
System.out.printf("%c ", node.data);
if(node.rightNode != null) {
nodeStack.push(node.rightNode);
}
if(node.leftNode != null) {
nodeStack.push(node.leftNode);
}
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com
Do we have a better way?
Could we save some space on the stack?
Do we need to push both children to the stack?
Copyright © 直通硅谷
http://www.zhitongguigu.com
public static void PreOrder2(Node root) {
Stack<Node> nodeStack = new Stack<Node>();
nodeStack.push(root);
Node node = root;
while(!nodeStack.empty()) {
System.out.printf("%c ", node.data);
if(node.rightNode != null) {
nodeStack.push(node.rightNode);
}
if(node.leftNode != null) {
node = node.leftNode;
} else {
node = nodeStack.pop();
}
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com
InOrder: What we should do?
InOrder: We push the node, go to left
If there is no left, we pop, print and push the right
Copyright © 直通硅谷
http://www.zhitongguigu.com
public static void InOrder(Node root) {
Stack<Node> nodeStack = new Stack<Node>();
Node node = root;
while(!nodeStack.empty() || node != null) {
if(node != null) {
nodeStack.push(node);
node = node.leftNode;
} else {
node = nodeStack.pop();
System.out.printf("%c ", node.data);
node = node.rightNode;
}
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com
PostOrder: The most difficult one
PostOrder: go to left, when there is no left, visit it. Then for the top of the stack, do we visit it now?
No. Because it is what InOrder does
We need to then go to the right until there is nowhere to go, we visit it and then pop
Copyright © 直通硅谷
http://www.zhitongguigu.com
PostOrder: The most difficult one
Can we do the PostOrder just using the current structure?
No. We do not know the status of the top element in the stack. Has the right child been traversed or not?
Copyright © 直通硅谷
http://www.zhitongguigu.com
We need an additional flag to store the status of the node
static class NodeWithFlag {
Node node;
boolean flag;
public NodeWithFlag(Node n, boolean value) {
node = n;
flag = value;
}
}
After we visit the right child, we update the flag;
Copyright © 直通硅谷
http://www.zhitongguigu.com
public static void PostOrder(Node root) {
Stack<NodeWithFlag> nodeStack = new Stack<NodeWithFlag>();
Node curNode = root;
NodeWithFlag newNode;
while(!nodeStack.empty() || curNode != null) {
while(curNode != null) {
newNode = new NodeWithFlag(curNode, false);
nodeStack.push(newNode);
curNode = curNode.leftNode;
}
newNode = nodeStack.pop();
curNode = newNode.node;
if(!newNode.flag) {
newNode.flag = true;
nodeStack.push(newNode);
curNode = curNode.rightNode;
} else {
System.out.printf("%c ", curNode.data);
curNode = null;
}
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com
If we have a traversal result of a tree, can we construct the tree?
PreOrder: A B C D
A
B
D
C
A
B
D
C
Copyright © 直通硅谷
http://www.zhitongguigu.com
No matter if you give a PreOrder, InOrder or PostOrder, it can construct different trees
What if we give two traversals?
Copyright © 直通硅谷
http://www.zhitongguigu.com
PreOrder: A B C D
A
B
D
C
A
B
D
C
InOrder: B A D C
Copyright © 直通硅谷
http://www.zhitongguigu.com
PreOrder: A B C D
A
B
D
C
PostOrder: B D C A
A
B
D
C
Copyright © 直通硅谷
http://www.zhitongguigu.com
Conclusion: You need two traversals to construct a tree, and one of them must be a InOrder traversal
How to construct a tree with a PreOrder and an InOrder?
A
B
D
E
H
I
J
G
F
C
Copyright © 直通硅谷
http://www.zhitongguigu.com
A is root so A is the first in PreOrder, InOrder can use A to seperate left sub-tree and right sub-tree
Then we can do recursion
Index : 0 1 2 3 4 5 6 7 8 9
PreOrder: A B D E H I C F G J
InOrder : D B H E I A F C G J
Copyright © 直通硅谷
http://www.zhitongguigu.com
public class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder.length == 0 || inorder.length == 0) {
return null;
}
int val = preorder[0];
TreeNode node = new TreeNode(val);
int i = 0;
for (; i < inorder.length; i++) {
if (inorder[i] == val) {
break;
}
}
node.left = buildTree(Arrays.copyOfRange(preorder, 1, i + 1),
Arrays.copyOfRange(inorder, 0, i));
node.right = buildTree(Arrays.copyOfRange(preorder, i + 1, preorder.length),
Arrays.copyOfRange(inorder, i + 1, inorder.length));
return node;
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com
public TreeNode buildTree(int[] preorder, int[] inorder) {
int preStart = 0;
int preEnd = preorder.length-1;
int inStart = 0;
int inEnd = inorder.length-1;
return construct(preorder, preStart, preEnd, inorder, inStart, inEnd);
}
public TreeNode construct(int[] preorder, int preStart, int preEnd,
int[] inorder, int inStart, int inEnd){
if(preStart > preEnd || inStart > inEnd){
return null;
}
int val = preorder[preStart];
TreeNode p = new TreeNode(val);
int i = inStart;
for(; i <= inEnd; i++){
if(val == inorder[i]){
break;
}
}
p.left = construct(preorder, preStart+1, preStart+(i-inStart), inorder, inStart, i-1);
p.right= construct(preorder, preStart+(i-inStart)+1, preEnd, inorder, i+1, inEnd);
return p;
}
A
B
D
E
H
I
J
G
F
C
PostOrder: D H I E B F J G C A
InOrder: D B H E I A F C G J
Copyright © 直通硅谷
http://www.zhitongguigu.com
It is similar as PreOrder + InOrder, the only difference is the root now is the last one in PostOrder
Copyright © 直通硅谷
http://www.zhitongguigu.com
public TreeNode buildTree(int[] inorder, int[] postorder) {
int inStart = 0;
int inEnd = inorder.length - 1;
int postStart = 0;
int postEnd = postorder.length - 1;
return build(inorder, inStart, inEnd, postorder, postStart, postEnd);
}
public TreeNode build(int[] inorder, int inStart, int inEnd, int[] postorder, int postStart, int postEnd) {
if (inStart > inEnd || postStart > postEnd)
return null;
int rootValue = postorder[postEnd];
TreeNode root = new TreeNode(rootValue);
int k = 0;
for (int i = inStart; i <=inEnd; i++) {
if (inorder[i] == rootValue) {
k = i;
break;
}
}
root.left = build(inorder, inStart, k - 1, postorder, postStart,
postStart + k - (inStart + 1));
root.right = build(inorder, k + 1, inEnd, postorder, postStart + k- inStart, postEnd - 1);
return root;
}
Copyright © 直通硅谷
http://www.zhitongguigu.com
Given a binary tree, return the inorder traversal of its nodes' values.
For example:
Given binary tree [1,null,2,3],
return [1,3,2].
Note: Recursive solution is trivial, could you do it iteratively?
1
\
2
/
3
Recursion:
O(n); O(log(n))
Stack:
O(n); O(log(n))
?:
O(n); O(1)
Copyright © 直通硅谷
http://www.zhitongguigu.com
Copyright © 直通硅谷
http://www.zhitongguigu.com
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
while (root != null) {
if (root.left != null) { // Not left end
TreeNode temp = root.left;
while (temp.right != null && temp.right != root) {
temp = temp.right;
}
if (temp.right == null) { // Build bridge
temp.right = root;
root = root.left;
} else { // Destroy bridge, add root, go right
temp.right = null;
result.add(root.val);
root = root.right;
}
} else { // Left end
result.add(root.val);
root = root.right;
}
}
return result;
}
Copyright © 直通硅谷
http://www.zhitongguigu.com
1
\
2
/
3
1
\
2
\
3
1
/
2
/
3
1
/
2
\
3
Each time I call, it should return the same tree.
Copyright © 直通硅谷
http://www.zhitongguigu.com
30
18
13
24
22
27
47
40
31
34
In order?
Copyright © 直通硅谷
http://www.zhitongguigu.com
Copyright © 直通硅谷
http://www.zhitongguigu.com
Copyright © 直通硅谷
http://www.zhitongguigu.com
30
18
13
24
22
27
47
40
31
34
Find 24
Find 42
Copyright © 直通硅谷
http://www.zhitongguigu.com
public static boolean find(int value, Node root) {
Node node = root;
while(node != null) {
if(node.data > value) {
node = node.leftNode;
}
else if(node.data < value) {
node = node.rightNode;
}
else return true;
}
return false;
}
Copyright © 直通硅谷
http://www.zhitongguigu.com
30
18
13
24
22
27
47
40
31
34
Add 42
Copyright © 直通硅谷
http://www.zhitongguigu.com
30
18
13
24
22
27
47
40
31
34
30
18
13
24
22
27
47
40
31
34
42
Copyright © 直通硅谷
http://www.zhitongguigu.com
public static boolean add(int value, Node root) {
if(root == null) {
root = new Node(value);
return true;
}
Node node = root;
while(node != null) {
if(node.data > value) {
if(node.leftNode != null) {
node = node.leftNode;
} else {
node.leftNode = new Node(value);
return true;
}
} else if(node.data < value) {
if(node.rightNode != null) {
node = node.rightNode;
} else {
node.rightNode = new Node(value);
return true;
}
}
else return false;
}
return false;
}
Copyright © 直通硅谷
http://www.zhitongguigu.com
What is the time complexity for finding and adding some element into the tree?
Copyright © 直通硅谷
http://www.zhitongguigu.com
30
18
13
24
22
27
47
40
31
34
Remove 27
Remove 30
Copyright © 直通硅谷
http://www.zhitongguigu.com
Copyright © 直通硅谷
http://www.zhitongguigu.com
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
Copyright © 直通硅谷
http://www.zhitongguigu.com
P
Q
R1
R2
if we remove Q, which is the best substitute?
Copyright © 直通硅谷
http://www.zhitongguigu.com
P
Q
R1
R2
Consider the inOrder traversal, the one just before Q and the one just after Q are the best candidates, since if they replace Q, when we do the inOrder again, the output is still an sorted array, which means the tree is still a BST.
So where are these two nodes?
Copyright © 直通硅谷
http://www.zhitongguigu.com
P
Q
R1
R2
So for the element before Q, it is the largest node in sub-tree R1
The element after Q, it is the smallest node in sub-tree R2
Does that node have child? Canwe remove them directly
Maybe, but at most one, so we go back to condition 2
Copyright © 直通硅谷
http://www.zhitongguigu.com
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;
}
Copyright © 直通硅谷
http://www.zhitongguigu.com
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;
}
Copyright © 直通硅谷
http://www.zhitongguigu.com
30
18
13
24
22
27
47
40
31
34
42
43
30
18
13
24
22
27
47
43
34
40
42
31
Copyright © 直通硅谷
http://www.zhitongguigu.com
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.
Copyright © 直通硅谷
http://www.zhitongguigu.com
Required