220 likes | 233 Views
Explore Binary Search Trees (BST) data structure for efficient element manipulation and retrieval. Learn how to implement BST algorithms and understand the runtime of searches and insertions. Discover common pitfalls and best practices in BST implementation.
E N D
Binary Search Trees • Rick Mercer, Allison Obourn, Marty Stepp
Binary Search Trees • A Binary Search Tree (BST) data structure is a binary tree with an ordering property • BSTs are used to maintain order and faster retrieval, insertion, and removal of individual elements • A Binary Search Tree (BST) is • an empty tree • consists of a node called the root, and two children, left and right, each of which are themselves binary search trees. Each BST contains a key at the root that is greater than all keys in the left BST while also being less than all keys in the right BST. Key fields are unique, duplicates not allowed.
A Binary Search Treeintegers represent the keys root • 50 • 25 • 75 • 12 • 35 • 66 • 90 • 28 • 41 • 54 • 81 • 95 • 91 • 100
Are these BSTs?only the keys are shown root • 50 • Is this a BST? • 25 • 75 • 12 • 45 • 66 • 90 root • 50 • Is this a BST? • 25 • 75 • 12 • 55 • 73 • 90
BST Algorithms only the keys are shown • Think about an algorithm that search for 36 • It is similar to Binary Search • Start at root • root • t • 50 • 25 • 75 • 12 • 36 • 65 • 90
adding Elements no duplicates can ever be added • The search element 36 < 50 so go left • root • t • 50 • 25 • 75 • 12 • 36 • 65 • 90
adding Elements no duplicates can ever be added 36 > 25 so go right36 found, stop, return true • root • t • 50 • 25 • 75 • 12 • 36 • 65 • 90
adding Elements no duplicates can ever be added If we were looking for 29, we would go to t.left and set t to null, return false What is the runtime of search in a BST? • root • t • 50 • 25 • 75 • 12 • 36 • 65 • 90
Insert • But how did we build this tree? • Don’t want to hard code it • There is no prefix expression to be used • Could be recursive • Could be iterative • Since trees are recursive data structures, we’ll use recursion
First, example insert 11 elements 20 75 11 98 31 23 39 80 150 77 • What a binary search tree would look like if these values were added in this order (first element is always at root) 50 20 75 98 80 31 150 39 23 11 77 root 50
Exercise root 55 29 87 -3 42 60 91 49 • Add a method add to the SearchTree class that inserts an element into the BST. • Add the new value in the proper place to maintain BST ordering bst.insert(49);
An incorrect solution root 55 29 87 -3 42 60 91 public void insert(E element) { add(root, element); } private void add(TreeNode t, E value) { if (t == null) { t = new TreeNode(value); else if (value.compareTo(t.data) < 0) add(t.left, value); else if (value.compareTo(t.data) > 0) add(t.right, value); // else t.data.equals(value), so // it's a duplicate (don't add) } • Why doesn't this solution work?
Change a point? x 1 y 2 p • Will the assertions pass? @Test public void testChange() { Point p = new Point(1, 2); change(p); assertEquals(3, p.x); assertEquals(4, p.y); } public void change(Point thePoint) { thePoint.x = 3; thePoint.y= 4; }
Change a point? x x 1 3 y y 2 4 p • Will the assertions pass? @Test public void testChange() { Point p = new Point(1, 2); change(p); assertEquals(3, p.x); assertEquals(4, p.y); } public void change(Point thePoint) { thePoint= new Point(3, 4); }
Changing references • If a method dereferences a variable (with . ) and modifies the object it refers to, that change will be seen by the caller void change(Point thePoint) { thePoint.x = 3; // affects the argument thePoint.y = 4; // affects the argument • If a method reassigns a variable to refer to a new object, that change will not affect the variable void change(Point thePoint) { thePoint= new Point(3, 4); // argument unchanged thePoint = null; // argument unchanged
Change point, version 3 x x 1 3 y y 2 4 p • Will these assertions pass? @Test public void testChange() { Point p = new Point(1, 2); change(p); assertEquals(3, p.x); assertEquals(4, p.y); } public Pointchange(Point thePoint) { thePoint= new Point(3, 4); return thePoint; }
Change point, version 4 x x 1 3 y y 2 4 • Will these assertions pass? @Test public void testChange() { Point p = new Point(1, 2); p = change(p); assertEquals(3, p.x); assertEquals(4, p.y); } public Point change(Point thePoint) { thePoint = new Point(3, 4); return thePoint; } p
The algorithmic pattern x = change(x); • If you want to write a method that can change the object that a variable refers to, you must do three things: • pass in the original state of the object to the method • return the new (possibly changed) object from the method • re-assignthe caller's variable to store the returned result p = change(p); public Point change(Point thePoint) { thePoint= new Point(99, -1); return thePoint; • Also seen with strings, methods return a new String s = s.toUpperCase();s = s.substring(0, 3);
The problem was 49 t root 55 29 87 -3 42 60 91 • Much like with linked structure, if we only modify what a local variable refers to, it won't change the collection private void add(TreeNode t, E value) { if (node == null) { node = new TreeNode(value); } • In linked structures, how did weactually modify the object? • by changing first • by changing a Node's next field
Applying x = change(x) • Methods that modify a tree should have the following pattern: • input (parameter): old state of the node • output (return): new state of the node parameter return node before node after your method • To change the tree, we must reassign t = change(t, parameters); t.left = change(t.left, parameters); t.right = change(t.right, parameters); root = change(root, parameters);
A correct solution root 55 29 87 -3 42 60 91 // Insert the given element into this BST publicvoid insert(E el) { • root = insert(root, el); • } • privateTreeNodeinsert(TreeNodet, E el) { • if (t == null) • t = newTreeNode(el); • elseif (el.compareTo(t.data) < 0) • t.left = insert(t.left, el); • else • t.right = insert(t.right, el); • returnt; • } • What happens when t is a leaf?