Tree

Copyright © 直通硅谷

http://www.zhitongguigu.com

Tree

Copyright © 直通硅谷

http://www.zhitongguigu.com

  • Tree
  • Binary Tree
    • Traversal
    • Construct
  • Binary Search Tree

Definition

Copyright © 直通硅谷

http://www.zhitongguigu.com

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

Tree

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

Tree

Copyright © 直通硅谷

http://www.zhitongguigu.com

Tree

B Tree

Trie Tree

Binary Tree

BST

RB Tree

AVL

Terminology

Copyright © 直通硅谷

http://www.zhitongguigu.com

  • Root
  • Node (internal node)
  • Leaf (external node)
  • Parent
  • Child
  • Siblings
  • Ancestor
  • Descendant

 

  • Edge (N - 1)
  • Path
  • Height
  • Depth
  • Level (D + 1)

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?

Binary Tree

Copyright © 直通硅谷

http://www.zhitongguigu.com

  • Traversal
    • pre
    • in
    • post
  • Construct
    • pre + in
    • post + in
    • pre + post

CMU

Binary Tree

  • It is actually different from tree
  • It has right sub-tree and left sub-tree
  • Each node can have at most two children

Copyright © 直通硅谷

http://www.zhitongguigu.com

Complete Binary Tree

  • Very useful in algorithm problems
  • Always assuming as a tree's property to compute the time complexity
  • The sum of the paths are the smallest

Copyright © 直通硅谷

http://www.zhitongguigu.com

Full [Binary] Tree

Heap is a complete [binary] tree

Properties of Binary Tree

  • at Level i, at most 2^i nodes
  • a tree with height k, at most 2^k-1 nodes
  • a complete binary tree with n nodes, the height will be 
  • If we number the node from root and base on the level, for a complete binary tree, we will have:
    • for node number k, the left child is 2k+1
    • for node number k, the right child is 2k+2
  • How to store a Binary Tree? a Complete Binary Tree?

Copyright © 直通硅谷

http://www.zhitongguigu.com

\left \lceil log_2(n+1) \right \rceil
log2(n+1)\left \lceil log_2(n+1) \right \rceil

Misuse of height

  • height -- internal nodes
  • level -- all nodes

Basic Data Structure of a Binary Tree

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;
    }
}

Traversal of a Binary Tree

  • PreOrder: Parent, left child, right child
  • InOrder: left child, Parent, right child
  • PostOrder: left child, right child, Parent

Copyright © 直通硅谷

http://www.zhitongguigu.com

Traversal 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

Copyright © 直通硅谷

http://www.zhitongguigu.com

Traversal of a Binary Tree

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);  
    }  
}  

Traversal of a Binary Tree

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);    
    }  
}  

Traversal of a Binary Tree

Copyright © 直通硅谷

http://www.zhitongguigu.com

Can we use Stack to traverse the tree without recursion?

Traversal of a Binary Tree

Copyright © 直通硅谷

http://www.zhitongguigu.com

PreOrder: visit, push left, push right?

PreOrder: visit, push right, push left

 

Because we need to visit left first

Traversal of a Binary Tree

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);
        }
    }
}

Traversal of a Binary Tree

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?

Traversal of a Binary Tree

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();
        }
    }
}

Traversal of a Binary Tree

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

Traversal of a Binary Tree

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;
        }
    }
}

Traversal of a Binary Tree

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

Traversal of a Binary Tree

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?

 

Traversal of a Binary Tree

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;

Traversal of a Binary Tree

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;
        }
    }
}

Construct a Binary Tree

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

Construct a Binary Tree

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?

Construct a Binary Tree

Copyright © 直通硅谷

http://www.zhitongguigu.com

PreOrder: A B C D

A

B

D

C

A

B

D

C

InOrder: B A D C

Construct a Binary Tree

Copyright © 直通硅谷

http://www.zhitongguigu.com

PreOrder: A B C D

A

B

D

C

PostOrder: B D C A

A

B

D

C

Construct a Binary Tree

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?

Construct a Binary Tree

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

PreOrder + InOrder

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;
    }
}

PreOrder + InOrder

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;
}

Construct a Binary Tree

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

PostOrder + InOrder

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;
}

Binary Tree Inorder Traversal

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)

Morris Traversal

Copyright © 直通硅谷

http://www.zhitongguigu.com

Morris Traversal

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;
}

Construct Binary Tree from Preorder and Postorder Traversal

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.

Binary Search Tree

Copyright © 直通硅谷

http://www.zhitongguigu.com

30

18

13

24

22

27

47

40

31

34

In order?

Binary Search Tree

  • All the sub-tree 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

Copyright © 直通硅谷

http://www.zhitongguigu.com

Binary Search Tree

  • Find
  • Add
  • Remove

Copyright © 直通硅谷

http://www.zhitongguigu.com

Binary Search Tree

Copyright © 直通硅谷

http://www.zhitongguigu.com

30

18

13

24

22

27

47

40

31

34

Find 24

  • 30 > 24 -> go to left
  • 18 < 24 -> go to right
  • find 24, return true

Find 42

  • 30 < 42 -> go to right
  • 34 < 42 -> go to right 
  • 40 < 42 -> go to right
  • 47 > 42 -> go to left
  • nothing on left, return false

Binary Search Tree

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;
}

Binary Search Tree

Copyright © 直通硅谷

http://www.zhitongguigu.com

30

18

13

24

22

27

47

40

31

34

Add 42

  • First we need to make sure if there is 42 in the tree already
  • Find the place we put 42

Binary Search Tree

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

Binary Search Tree

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;
}

Binary Search Tree

Copyright © 直通硅谷

http://www.zhitongguigu.com

What is the time complexity for finding and adding some element into the tree?

Binary Search Tree

Copyright © 直通硅谷

http://www.zhitongguigu.com

30

18

13

24

22

27

47

40

31

34

Remove 27

  • First we need to make sure if there is 27 in the tree already
  • We need to remove 27

Remove 30

  • How do we remove something that is not a leaf?

Binary Search Tree

Copyright © 直通硅谷

http://www.zhitongguigu.com

  • If Q is a leaf
  • If Q has one child
    • if the child R is the right child
    • if the child R is the left child
  • if Q has two children

Binary Search Tree

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

Binary Search Tree

Copyright © 直通硅谷

http://www.zhitongguigu.com

P

Q

R1

R2

if we remove Q, which is the best substitute?

Binary Search Tree

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?

Binary Search Tree

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;
}

Binary Search Tree(cont)

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;
}

Binary Search Tree

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

Binary Search Tree

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.

Homework

Copyright © 直通硅谷

http://www.zhitongguigu.com

Made with Slides.com