Week 7 Search Tree Data Structures
Week 7 Search Tree Data Structures
1/63
Searching
An extremely common application in computing
Cost of searching:
Also (cf. COMP9021): hash tables (O(1), but only under optimal conditions)
4/63
Tree Data Structures
Trees are connected graphs
!"consisting of nodes and edges (called links), with no cycles (no "up-links")
!"each node contains a data value (or key+data)
!"each node has links to ≤ k other child nodes (k=2 below)
Binary trees (k=2 children per node) can be defined recursively, as follows:
9/63
Search Trees
10/63
Binary Search Trees
Binary search trees (or BSTs) have the characteristic properties
Operations on BSTs:
Notes:
(a) 4 2 6 5 1 7 3
(b) 6 5 2 3 4 7 1
(c) 1 2 3 4 5 6 7
16/63
Representing BSTs
Binary trees are typically represented by node structures
Tree Algorithms
20/63
Searching in BSTs
Most tree algorithms are best described recursively
TreeSearch(tree,item):
| Input tree, item
| Output true if item found in tree, false otherwise
|
| if tree is empty then
| return false
| else if item < data(tree) then
| return TreeSearch(left(tree),item)
| else if item > data(tree) then
| return TreeSearch(right(tree),item)
| else // found
| return true
| end if
21/63
Insertion into BSTs
Insert an item into appropriate subtree
insertAtLeaf(tree,item):
| Input tree, item
| Output tree with item inserted
|
| if tree is empty then
| return new node containing item
| else if item < data(tree) then
| return insertAtLeaf(left(tree),item)
| else if item > data(tree) then
| return insertAtLeaf(right(tree),item)
| else
| return tree // avoid duplicates
| end if
22/63
Tree Traversal
Iteration (traversal) on …
!"preorder (NLR) … visit root, then left subtree, then right subtree
!"inorder (LNR) … visit left subtree, then root, then right subtree
!"postorder (LRN) … visit left subtree, then right subtree, then root
!"level-order … visit root, then all its children, then all their children
NLR (preorder): 20 10 5 2 14 12 17 30 24 29 32 31
LNR (inorder): 2 5 10 12 14 17 20 24 29 30 31 32
LRN (postorder): 2 5 12 17 14 10 29 24 31 32 30 20
showBSTreePreorder(t):
| Input tree t
|
| push t onto new stack S
| while stack is not empty do
| | t=pop(S)
| | print data(t)
| | if right(t) is not empty then
| | push right(t) onto S
| | end if
| | if left(t) is not empty then
| | push left(t) onto S
| | end if
| end while
28/63
Joining Two Trees
An auxiliary tree operation …
!"Pre-conditions:
#"takes two BSTs; returns a single BST
#"max(key(t1)) < min(key(t2))
!"Post-conditions:
#"result is a BST (i.e. fully ordered)
#"containing all items from t1 and t2
Implementation of tree-join
joinTrees(t1,t2):
| Input trees t1,t2
| Output t1 and t2 joined together
|
| if t1 is empty then return t2
| else if t2 is empty then return t1
| else
| | curr=t2, parent=NULL
| | while left(curr) is not empty do // find min element in t2
| | parent=curr
| | curr=left(curr)
| | end while
10
| | if parent≠NULL then
| | left(parent)=right(curr) // unlink min element from parent
| | right(curr)=t2
| | end if 7
| | left(curr)=t1
| | return curr // curr is new root 8
| end if
7 32/63
Exercise #4: Joining Two Trees
t1
8
34/63
Deletion from BSTs
Insertion into a binary search tree is easy.
Version 1: right child becomes new root, attach left subtree to min element of right subtree
TreeDelete(t,item):
| Input tree t, item
| Output t with item deleted
|
| if t is not empty then // nothing to do if tree is empty
| | if item < data(t) then // delete item in left subtree
| | left(t)=TreeDelete(left(t),item)
| | else if item > data(t) then // delete item in right subtree
| | right(t)=TreeDelete(right(t),item)
| | else // node 't' must be deleted
| | | if left(t) and right(t) are empty then
| | | new=empty tree // 0 children
| | | else if left(t) is empty then
| | | new=right(t) // 1 child
| | | else if right(t) is empty then
| | | new=left(t) // 1 child
| | | else
| | | new=joinTrees(left(t),right(t)) // 2 children
| | | end if
| | | free memory allocated for current node t
| | | t=new
| | end if
| end if
| return t
44/63
Balanced Binary Search Trees
Goal: build binary search trees which have
Left: 5
Right: 1
Diff: 4 ≥ 1
45/63
Operations for Rebalancing
To assist with rebalancing, we consider new operations:
Left rotation
Right rotation
Insertion at root
46/63
Tree Rotation
In tree below: t1 < n2 < t2 < n1 < t3
rotateRight(n1):
| Input tree n1
| Output n1 rotated to the right
|
| if n1 is empty or left(n1) is empty then
| return n1
| end if N2 = New root node
| n2=left(n1)
| left(n1)=right(n2)
| right(n2)=n1
| return n2
rotateLeft(n2):
| Input tree n2
| Output n2 rotated to the left
|
| if n2 is empty or right(n2) is empty then
| return n2
| end if
| n1=right(n2)
| right(n2)=left(n1)
| left(n1)=n2
| return n1
53/63
Insertion at Root
Previous description of BSTs inserted at leaves.
Potential disadvantages:
Potential advantages:
!"base case:
#"tree is empty; make new node and make it root
!"recursive case:
#"insert new node as root of appropriate subtree
#"lift new node to root by rotation
... Insertion at Root 55/63
Analysis of insertion-at-root:
!"SetInsert(Set,Item) ≡ TreeInsert(Tree,Item)
!"SetDelete(Set,Item) ≡ TreeDelete(Tree,Item.Key)
!"SetMember(Set,Item) ≡ TreeSearch(Tree,Item.Key)
Concrete representation:
#include "BSTree.h"
Set newSet() {
Set S = malloc(sizeof(SetRep));
assert(S != NULL);
S->nelems = 0;
S->root = newTree();
return S;
}
63/63
Summary
!"Binary search tree (BST) data structure
!"Tree traversal
!"Basic BST operation: insertion, join, deletion, rotation
!"Suggested reading:
#"Sedgewick, Ch. 12.5-12.6, 12.8