Lecture 12 CS203 1
Binary Trees A list, stack, or queue is a linear structure that consists of a sequence of elements. A binary tree is a hierarchical structure. It is either empty or consists of an element, called the root, and two distinct binary trees, called the left subtree and right subtree. 2
Binary Tree Terms The root of left (right) subtree of a node is called a left (right) child of the node. A node without children is called a leaf. A special type of binary tree called a binary search tree is often useful. A binary search tree (with no duplicate elements) has this property: for every node in the tree, the value of any node in its left subtree is less than the value of the node and the value of any node in its right subtree is greater than the value of the node. Note that this requires a way to order the elements, so in Java we usually either build trees of Comparables or use Comparators This section is concerned with binary search trees, which, as the name suggests, allow you to easily implement binary search. 3
Representing Binary Trees A binary tree can be represented using a set of linked nodes. Each node contains a value and two links named left and right that reference the left child and right child, respectively, as shown in Figure 27.2. class TreeNode<E> { E element; TreeNode<E> left; TreeNode<E> right; public TreeNode(E o) { element = o; } 4
Searching an Element in a Binary Search Tree public boolean search(E element) { TreeNode<E> current = root; // Start from the root while (current != null) if (element < current.element) { current = current.left; // Go left } else if (element > current.element) { current = current.right; // Go right else // Element matches current.element return true; // Element is found return false; // Element is not in the tree 5
Inserting an Element to a Binary Search Tree If a BST is empty, create a root node with the new element. Otherwise, locate the parent node for the new element node. If the new element is less than the parent element, the node for the new element becomes the left child of the parent. If the new element is greater than the parent element, the node for the new element becomes the right child of the parent. 6
Inserting an Element to a BST if (root == null) root = new TreeNode(element); else { // Locate the parent node current = root; while (current != null) if (element value < the value in current.element) { parent = current; current = current.left; } else if (element value > the value in current.element) { current = current.right; else return false; // Duplicate node not inserted // Create the new node and attach it to the parent node if (element < parent.element) parent.left = new TreeNode(elemenet); parent.right = new TreeNode(elemenet); return true; // Element inserted Insert 101 into the following tree. 7
Trace Inserting 101 into the following tree, cont. if (root == null) root = new TreeNode(element); else { // Locate the parent node current = root; while (current != null) if (element value < the value in current.element) { parent = current; current = current.left; } else if (element value > the value in current.element) { current = current.right; else return false; // Duplicate node not inserted // Create the new node and attach it to the parent node if (element < parent.element) parent.left = new TreeNode(elemenet); parent.right = new TreeNode(elemenet); return true; // Element inserted Insert 101 into the following tree. 101 < 107 true 8
Inserting 59 into the Tree if (root == null) root = new TreeNode(element); else { // Locate the parent node current = root; while (current != null) if (element value < the value in current.element) { parent = current; current = current.left; } else if (element value > the value in current.element) { current = current.right; else return false; // Duplicate node not inserted // Create the new node and attach it to the parent node if (element < parent.element) parent.left = new TreeNode(elemenet); parent.right = new TreeNode(elemenet); return true; // Element inserted 9
Tree Traversal Tree traversal is the process of visiting each node in the tree exactly once. There are several ways to traverse a tree. This section presents inorder, preorder, postorder, depth-first, and breadth-first traversals. Inorder traversal visits the left subtree of the current node first recursively, then the current node itself, and finally the right subtree of the current node recursively. Postorder traversal visits the left subtree of the current node first, then the right subtree of the current node, and finally the current node itself. Preorder traversal visits the current node first, then the left subtree of the current node recursively, and finally the right subtree of the current node recursively. 10
Tree Traversal, cont. Breadth-first traversal visits the nodes level by level. First visit the root, then all children of the root from left to right, then grandchildren of the root from left to right, and so on. For example, in the tree below inorder is 45 55 57 59 60 67 100 101 107 postorder is 45 59 57 55 67 101 107 100 60. preorder is 60 55 45 57 59 100 67 107 101. breadth-first traversal is 60 55 100 45 57 67 107 59 101. 11
Tree After Insertions Inorder: Adam, Daniel George, Jones, Michael, Peter, Tom Postorder: Daniel Adam, Jones, Peter, Tom, Michael, George Preorder: George, Adam, Daniel, Michael, Jones, Tom, Peter 12
Deleting Elements in a Binary Search Tree To delete an element from a BST, first locate the node that contains the element and also its parent node. Let current point to the node that contains the element in the binary tree and parent point to the parent of the current node. The current node may be a left child or a right child of the parent node. 13
Deleting Elements in a Binary Search Tree Deleting an element that has one or more child nodes requires reconnecting the child nodes to the tree If there is only one child, just make that child the appropriate-side child of the parent of the node that was deleted 14
Deleting Elements in a Binary Search Tree For example, to delete node 10 in Figure 25.9a. Connect the parent of node 10 with the right child of node 10, as shown in Figure 25.9b. 15
Deleting Elements in a Binary Search Tree If the node deleted has two children, we need to restructure part of the tree in a way that maintains the BST ordering This can be done in either of two mirror-image ways. The procedure on the next few slides could be done just as well using LefMmost, ParentOfLeftMost, etc., in the right subtree. This procedure is different from the explanation in the book 16
Deleting Elements in a Binary Search Tree Case 2: The node to be deleted has two children Let rightMost point to the node that contains the largest element in the left subtree of the current node and parentOfRightMost point to the parent node of the rightMost node, as shown on the next slide. The rightMost node cannot have a right child, but may have a left child. Since rightMost and parentofRightMost (if it is not itself the node to be deleted) are in the left tree, they are left of the node to be deleted. Rightmost is the least left element in the left tree. All the other elements in the left subtree must remain left of rightmost, and all the elements in the right subtree must remain to the right of it. 17
Deleting Elements in a Binary Search Tree This algorithm preserves these properties while deleting current: Replace the element value in the current node with the one in the rightMost node Make the right child reference of parentOfRightMost refer to the left child of the rightMost node Delete the rightMost node 18
Deleting Elements in a Binary Search Tree 19
Deleting Elements in a Binary Search Tree 20
Examples 21
Examples 22
Examples 23
BST Time Complexity The time complexity for the inorder, preorder, and postorder is O(n), since each node is traversed only once The time complexity for search, insertion and deletion is the height of the tree; more on that below. 24
BST Time Complexity If there are at least two elements to be placed in a BST, the same data can generate different BSTs. If there are at least three nodes, it can generate BSTs with different heights. 1 2 2 1 3 3 25
BST Time Complexity Consider what happens if a BST is created from already-sorted data without any attempts at optimization: 1 Already-sorted data is not unusual! 2 3 4 26
BST Time Complexity A complete binary tree is one in which every level other than the lowest level is completely filled, and all nodes are as far to the left as possible: 27
BST Time Complexity If a tree is perfectly balanced, i.e., a complete binary tree, its height (number of levels minus 1) is the floor of log n. If it is completely unbalanced, its height is n-1 The time complexity for search, insertion and deletion is the height of the tree. In the worst case, it is O(n). In the best case it is O(log n). We want our trees to be balanced, so that we get the O(log n) behavior 28
Breadth First Traversal of a Binary Tree Breadth First Search is not a wise way to find a particular element in a binary search tree, since it does not take advantage of the (log n) binary search we can get in a well-balanced tree. However, the term is often used loosely to describe breadth-first traversal of an entire data structure. The most likely actual use case for BFS with a BST is to test whether your trees are being constructed correctly. Lab 7 will include a method to do a BFS of a data structure you will create yourself. Here is the algorithm: Create a permanent queue to hold all elements. Create another, temporary queue to hold elements that you are processing to find the BFS order. Add the root to the temporary queue. As long as there are node references in the temporary queue, poll them one at a time, add them to the permanent queue, and add any left or right references to the temporary queue When the last node is polled from the temporary queue, the permanent list is complete. 29
Breadth First Traversal Create a queue for unvisited nodes and a list for visited nodes Put the starting node at the back of the queue. While the queue is not empty: Take the front item of the queue and add it to the visited list. Create a list of that nodes neighbors nodes. Add those which have not already been visited to the back of the queue. The next two slides show BF traversal of a graph This slide and the next two use material from https://www.programiz.com/dsa/graph-bfs
Breadth First Traversal
Breadth First Traversal
Sets A Set differs from a List in these ways: 33 Sets A Set differs from a List in these ways: a Set does not (in general) have any inherent order a Set may not contain any duplicate elements This means that a set may not contain any two elements e1 and e2 such that e1.equals(e2) There are several types of Set in the Java Collections Framework. The most important ones are HashSet and TreeSet
AbstractSet and HashSet 34 AbstractSet and HashSet AbstractSet extends AbstractCollection and implements Set. AbstractSet provides implementations of equals() and hashCode(). The hash code of a set is the sum of the hash codes of all the elements in the set. Since the size method and iterator are not implemented in the AbstractSet class, AbstractSet is an abstract class. HashSet is a concrete class that implements Set and extends AbstractSet. Objects added to a HashSet need to implement the hashCode() method. You do not normally need to write this method yourself.
Attempts to add duplicate records to a set are ignored: 35 Duplicates Attempts to add duplicate records to a set are ignored: package demos; import java.util.HashSet; import java.util.Set; public class Demo { public static void main(String[] args) { Set<String> nameSet = new HashSet<String>(); nameSet.add("Brutus"); nameSet.add("Cicero"); nameSet.add("Spartacus"); printAll(nameSet); } public static <T> void printAll(Set<T> set){ System.out.println(" set contains these records: "); for(T t: set){ System.out.println(t);