Trees The Basics 1. A tree is a finite, non-empty set of nodes. T = {r} T1 T2 … Tn Where a designated node, r, is the root of the tree, and T1, T2, … Tn are zero or more non-empty trees, each of whose roots are connected by a directed edge from r. 2. The root of each (sub)tree is a child of r. 3. r is the parent of each (sub)tree’s root. r T1 T2 ... Tn ri ≈ Ti Ti1 Ti2 ... Tin A B C D H E I F J P K L G M N Q 4. Leaves are nodes with no children (e.g. B,C,H,I,P,Q,K,L,M,N). 5. Siblings are nodes with the same parent (e.g. K,L,M). 6. Depth of a node, ni, is the length of the unique path from r to ni (e.g. { A } = 0, { B,C,D,E,F,G } = 1, { H,I,J,K,L,M,N } = 2, { P,Q } = 3). 7. Height of a node, ni, is the length of the longest path from ni down to a leaf (e.g. { B,C,H,I,P,Q,K,L,M,N } = 0, { H,J,F,G } = 1, { E } = 2, { A } = 3). 8. Depth of a tree is equal to the depth of the deepest leaf, and is equal to the height of the root node. 9. n1 is an ancestor of n2 and n2 is a descendant of n1 if there is a path from n1 to n2 (e.g. A is an ancestor of all nodes, E is an ancestor of { I,J,P,Q }, J is an ancestor of { P,Q }, { P,Q } are descendants of { J,E,A }, J is a descendant of { E,A }, E is a descendant of A). Binary Trees A binary tree is a tree in which no node can have more than two children. r TL TR ri Ti ≈ TiL TiR Properties of binary trees 1. The depth of a binary tree containing N nodes is at most N-1. 2. The depth of a binary tree containing N leaves is at least [log2(N)]. 3. A binary tree of depth d has at most 2d leaves. 4. The number of nodes in a binary tree of depth d is at most 2d-1 - 1. 5. The average depth of a binary tree containing N nodes is Ο Ν . Tree Traversals Tree traversal is the process of systematically walking through the tree to visit all the nodes. A B D C E F H G I Depth-First Traversal Preorder Algorithm: Visit the root first (print). Do a left-to-right preorder traversal of each subtree. Code: Preorder(t) { if t == NULL return visit(t) Preorder(t->left) Preorder(t->right) } Example: A,B,C,D,E,F,G,H,I Inorder (only makes sense for binary trees) Algorithm: Do an inorder traversal of the left subtree. Visit the root (print). Do an inorder traversal of the right subtree. Code: Inorder (t) { if t == NULL return Inorder(t->left) visit(t) Inorder(t->right) } Example: B,C,A,F,E,G,D,I,H Postorder Algorithm: Do a left-to-right postorder traversal of each subtree. Visit the root (print). Code: Postorder(t) { if t == NULL return Postorder(t->left) Postorder(t->right) visit(t) } Example: C,B,F,G,E,I,H,D,A Breadth-First Traversal Algorithm: Visit all the nodes of depth 0 from left-to-right. Visit all the nodes of depth 1 from left-to-right. ... Visit all the nodes of depth n from left-to-right. Code (uses a queue): BreadthFirst(t) { while t != NULL visit (t) if t->left != NULL Enqueue(t->left, q) if t->right != NULL Enqueue(t->right, q) if NotEmpty(q) t = Dequeue(q) else t = NULL } Example: A,B,D,C,E,H,F,G,I