360 likes | 481 Views
Chapter 05. Trees (Part II). 5.2.3 Representations. Array Representation. We can use an array to represent a complete binary tree. Lemma 5.4 If a complete binary tree with n nodes in given, then for any node with index i, 1≦i≦n, Parent(i) is at if i > 1. If i=1, node i is the root.
E N D
Chapter 05 Trees (Part II)
Array Representation • We can use an array to represent a complete binary tree. • Lemma 5.4 • If a complete binary tree with n nodes in given, then for any node with index i, 1≦i≦n, • Parent(i) is at if i > 1. If i=1, node i is the root. • LeftChild(i) is at 2i if 2i≦n. • If 2i > n, node i has no left child. • RightChild(i) is at 2i+1 if 2i+1≦n. • If 2i+1 > n, node i has no right child.
Example 11 10 0 2 3 1 5 6 7 8 9 4 • Node 1: • Parent(1): 0, indicating node 1 is the root. • LeftChild(1): 2i = 2. • RightChild(2): 2i+1 = 3. • Node 5: • Parent(5): • LeftChild(5): • RightChild(5): • Node 4: • Parent(4): • LeftChile(4): • RightChild(4): 1 H E I D G B F C A A 2 3 B C 7 4 5 6 D E F G 8 9 H I Complete binary tree
Array Representation • Advantages: • Suppose n is the number of nodes. The search time can be bounded to O(log2n). • Disadvantages: • The utilization of memory space is not flexible enough.
Linked Representation class TreeNode { friend class Tree; private: int data; TreeNode *leftChild; TreeNode *rightChild; }; class Tree { public: //Tree operations private: TreeNode *root; }; leftChild data rightChild data leftChild rightChild
Introduction • Goal: to visit each node in a tree. • In each node, 6 possible ways can be used to move forwarding: • LVR, LRV, VLR, VRL, RVL, and RLV. • L: moving left. • V: visiting the node. • R: moving right. • Different traversal approaches result in different order of output.
Introduction • Conventionally, we traverse left before right. • LVR (Inorder traversal) • LRV (Postorder traversal) • VLR (Preorder traversal) 1 2 3 V 1 2 1 3 3 2 V V L R L L R R
5.3.2 Inorder Traversal void Tree::Inorder() { Inorder(root); } void Tree::Inorder(TreeNode *currentNode) { if (currentNode) { Inorder(currentNode->leftChild); Visit(currentNode); Inorder(currentNode->rightChild); } }
Example • Consider using a binary tree to represent the following expression. (((A / B) * C) * D) + E + + + * * * E E E * * * D D D / / / C C C A A A B B B Visiting order: A / B * C * D + E
5.3.2 Preorder Traversal • Approach: VLR void Tree::Inorder(TreeNode *currentNode) { if (currentNode) { Visit(currentNode); Inorder(currentNode->leftChild); Inorder(currentNode->rightChild); } } + + + * * * E E E * * * D D D / / / C C C A A A B B B + * * / A B C D E Visiting order:
5.3.2 Postorder Traversal • Approach: LRV void Tree::Inorder(TreeNode *currentNode) { if (currentNode) { Inorder(currentNode->leftChild); Inorder(currentNode->rightChild); Visit(currentNode); } } + + + * * * E E E * * * D D D / / / C C C A A A B B B Visiting order: A B / C * D * E +
5.3.5 Iterative Inorder Traversal • By using stack. void Tree::NonrecInorder() { Stack S; TreeNode *currentNode = root; while (1) { while (currentNode) { S.Push(currentNode); currentNode = currentNode->leftChild; } if (S.IsEmpty()) return; currentNode = S.Pop(); Visit(currentNode); currentNode = currentNode->rightChild; } } • When do we push into the stack? • When do we pop the stack?
5.3.5 Iterative Inorder Traversal currentNode: * NULL + A / B * • By using stack. + + A * * E B / * * * D * / / / C + Stack A A A B B B Visiting order: A / B
5.3.6 Level-Order Traversal • Visiting order in level-order traversal: 1 + 2 3 * E 4 5 * D 6 7 / C 8 9 A B
5.3.6 Level-Order Traversal • By using queue. void Tree::LevelOrder() { Queue Q; TreeNode *currentNode = root; while (currentNode) { Visit(currentNode); if (currentNode->leftChild) Q.Push(currentNode->leftChild); if (currentNode->rightChild) Q.Push(currentNode->rightChild); if (Q.IsEmpty()) return; currentNode = Q.Pop(); } }
5.6.1 Priority Queue • The element to be deleted is the one with highest (or lowest) priority. • Consider one insertion and one deletion for an ordered and a non-ordered list: • Using a heap, both insertion and deletion can be performed in O(logn) time where n is the number of elements in the list.
5.6.2 Definition of a Max Heap • A max tree is a tree which the data in each node is no smaller than those in its children. A max heap is a max tree which is a complete binary tree at once. 9 8 7 3 5 6 5 6 1 4 2 1 4
The ADT of MaxHeap • A heap can be implemented using array class MaxHeap { private: int *heap; //element array int heapSize; //number of elements in heap int capacity; //size of the array heap };
The Constructor for MaxHeap • Note: heap[0] is dummy. MaxHeap::MaxHeap(int theCapacity = 10) { if (theCapacity < 1) throw “Capacity must be >= 1.”; capacity = theCapacity; heapSize = 0; heap = new int [capacity + 1]; } 0 dummy The root is at heap[1]. 1 2 3 4 5 6 7
5.6.3 Insertion into a Max Heap • Example: Insert 5 into the heap 1 20 20 15 2 5 2 2 3 14 10 2 5 4 5 6 7 3 6 currentNode: Inititally: heapSize+1
5.6.3 Insertion into a Max Heap void MaxHeap::Push(int e) { if (heapSize+1 == capacity) Resize(); int currentNode = heapSize + 1; while (currentNode != 1 && heap[currentNode/2] < e) { heap[currentNode] = heap[currentNode / 2]; currentNode /= 2; } heap[currentNode] = e; }
Analysis of Push() • Time complexity: • The insertion begins at a leaf and moves up toward the root. • the height of a complete binary tree with n elements is , the while loop is iterated O(logn) times. • Each iteration of this loop takes O(1) time. • Hence, the time complexity of O(logn).
5.6.4 Deletion from a Max Heap • Example: delete 5 from the heap 1 1 2 4 currentNode: 20 2 15 20 The element to be popped: 15 15 2 14 5 2 3 14 2 14 10 2 4 5 6 7
5.6.4 Deletion from a Max Heap intMaxHeap::Pop(int e) { if (IsEmpty()) throw “Heap is empty.”; intlastE = heap[heapSize – -]; intcurrentNode = 1; //root int Max = heap[currentNode]; int child = 2; //a child of currentNode while (child <= heapSize) { if (child < heapSize && heap[child] < heap[child+1]) child++; if (lastE >= heap[child]) break ; heap[currentNode] = heap[child]; currentNode = child; child *= 2; } heap[currentNode] = lastE; return Max; }
Analysis of Pop() • Time complexity: • Suppose the number of elements in the heap is n. • Since the height of a heap is , the while loop is iterated O(logn) times. • Each iteration of this loop takes O(1) time. • Hence, the time complexity of pop() is O(logn).
5.6 Binary Search Tree Part I – Searching and Insertion
5.7.1 Defintion • A binary search tree has the following properties: • The keys in all nodes are distinct. • The key in any node is larger than all keys in its left subtree. • The key in any node is smaller than all keys in its right subtree. • The left and right subtrees are also binary trees.
Examples • Examples of binary search tree 20 30 60 40 70 25 5 15 2 65 80 12 16 26 By using which traversal approach can we output the keys in increasing order?
5.7.2 Searching a Binary Search Tree • Point: searching a binary tree in a recursive way. bool BST::Search(int k) { return Get(root, k); } bool BST::Search (TreeNode *p, int k) { if (!p) return false; if (p->key == k) return true; if (k < p->key) return Search (p->leftChild, k); if (k > p->key) return Search (p->rightChild, k); }
5.7.2 Searching a Binary Search Tree • Searching a binary tree in an iterative way. bool BST::IterativeSearch (int k) { TreeNode *currentNode = root; while (currentNode) { if (k == currentNode->data) return true; if (k < currentNode->data) currentNode = currentNode->leftChild; if (k > currentNode->data) currentNode = currentNode->rightChild; } return false; }
Comparison • Suppose h denote the depth of the tree.
5.7.3 Insertion into a Binary Search Tree • Point: to find the position to insert first. • If there is a duplicate key, then the insertion will not be performed. • Consider to insert 35 into the tree: 30 30 40 40 5 5 2 2 16 16 80 80 35
5.7.3 Insertion into a Binary Search Tree bool BST::Insert (int k) { TreeNode *p = root, **pp = NULL; while (p) { pp = p; if (k == p->data) return false; if (k < p->data) p = p->leftChild; if (k > p->data) p = p->rightChild; } p = new TreeNode(k); if (root) { if (k < pp->key) pp->leftChild = p; else (k > pp->key) pp->RightChild = p; } else root = p; return false; }