CS 261: Data Structures

Binary Traversals Binary Search Trees

1 Traversals • How to examine nodes in a tree? • A list is a simpler structure: – can be traversed either forward or backward

• What order do we visit nodes in a tree?

• Most common tree traversal orders: –Pre-order –In-order –Post-order

2 Binary Tree Traversals • All traversal algorithms have to: – Process node – Process left subtree – Process right subtree

Traversal order is determined by the order these operations are done

3 Binary Tree Traversals – Most Common

1.Node, left, right à Pre-order 2.Left, node, right à In-order 3.Left, right, node à Post-order

4 Pre-Order Binary Tree Traversal

• Process order à Node, Left subtree, Right subtree

p void preorder(struct Node *node) { if (node != 0){ process (node->val); s e preorder(node->left); preorder(node->rght); } a m l r } a t e

Example result: p s a m a e l r t e e e

5 Post-Order Binary Tree Traversal

• Process order à Left subtree, Right subtree, Node

p void postorder(struct Node *node) { if (node != 0){ s e postorder(node->left); postorder(node->rght); process(node->val); a m l r } } a t e

Example result: a a m s l t e e r e p e

6 In-Order Binary Tree Traversal

• Process order à Left subtree, Node, Right subtree

p void inorder(struct Node *node) { if (node != 0){ inorder(node->left); s e process(node->val); inorder(node->rght); a m l r } } a t e

Example result: a s a m p l e t r e e e

7 Complexity of Binary Tree Traversals • Each traversal requires constant work at each node (not including recursive calls) • Order not important • Iterating over all n elements in a tree requires O(n) time

8 Binary Search Trees

9 • = Binary trees where every node value is: –Greater than all its left descendants –Less than or equal to all its right descendants –In-order traversal returns elements in sorted order

• If tree is reasonably full (well balanced), searching for an element is O(log n)

10 Binary Search Tree: Example

Alex

Abner Angela

Abigail Adela Alice Audrey

Adam Agnes Allen Arthur

11 A Node in BST

struct Node { TYPE val; struct Node *left; /* Left child */ struct Node *right; /* Right child */ };

12 Binary Search Tree (BST): Implementation

struct BST { struct Node *root;

int size;

};

void initBST(struct BST *tree); int containsBST(struct BST *tree, TYPE val);

void addBST(struct BST *tree, TYPE val);

void removeBST(struct BST *tree, TYPE val);

int sizeBST(struct BST *tree);

13 Sorted Bag Implementation: Contains • Start at root • At each node, compare value to node value: –Return true if match –If value is less than node value, go to left child (and repeat) –If value is greater than node value, go to right child (and repeat) –If node is null, return false

14 Bag Implementation: Contains • Traverses a path from the root to the leaf • Therefore, if tree is reasonably full, execution time is O( ?? )

15 BST: Contains/Find Example

Alex Object to find Agnes

Abner Angela

Abigail Adela Alice Audrey

Adam Agnes Allen Arthur

16 BST: Add Example

Alex Object to add Aaron

Abner Angela

Abigail Adela Alice Audrey

Aaron Adam Agnes Allen Arthur

“Aaron” should be added here

17 Add: Calls a Utility Routine

void addBST(struct BST *tree, TYPE val) {

assert(tree);

tree->root = _addNode(tree->root, val);

tree->size++;

}

What is the complexity? O( ?? )

18 Useful Auxiliary Function -- Recursion struct Node * _addNode(struct Node * current, TYPE val){ if (current == 0) {/* always first check when to stop */

. . . /*make a new node and return the pointer to it*/ } else { /* call recursion left or right */ } return current; } return the same pointer

19 Useful Auxiliary Function -- Recursion struct Node * _addNode(struct Node * current, TYPE val){ if (current == 0){ . . . /*make a new node and return the pointer to it*/ }else{ if (val < current->val) /* recursion left */ current->left = _addNode(current->left, val); else /* recursion right */ current->right = _addNode(current->right, val); } return current; }

20 Useful Auxiliary Function struct Node * _addNode(struct Node * current, TYPE val){ if (current == 0){ struct Node * new = (struct Node *) malloc(sizeof(struct Node)); assert(new != 0); new->value = val; new->left = new->right = 0; return new; }else if (val < current->val) current->left = _addNode(current->left, val); else current->right = _addNode(current->right, val); return current; } 21 BST: Remove

Alex

Abner Angela

Abigail Adela Alice Audrey

Adam Agnes Allen Arthur

How would you remove: Audrey? Angela?

22 Who Fills the Hole in BST?

• Answer: the leftmost descendant of the right child = smallest element in the right subtree • Try this on a few values

23 BST: Remove Example

Element to Alex remove

Replace with: Abner leftmost right Angela

Abigail Adela Alice Audrey

Adam Agnes Allen Arthur

24 BST: Remove Example

Alex

Abner Arthur

Abigail Adela Alice Audrey

Adam Agnes Allen

After call to remove 25 Special Case • What if you don’t have the right child?

• Try removing “Audrey” –Simply, return the left child Angela

Alice Audrey

Allen Arthur

26 Remove

void removeBST (struct BST *tree, TYPE e) {

if (containsBST(tree, e)) {

tree->root = _removeNode(tree->root, e);

tree->size--;

}

}

27 Remove Node

struct Node *_removeNode(struct Node *current, TYPE e){

if (current->val == e)

/* Found it, remove it */

else

/* not found, so recursive call */

}

28 Remove Node struct Node *_removeNode(struct Node *current, TYPE e){ struct Node *node; assert(current); if (current->val == e) /* Found it, remove it */ if (current->right == NULL){ node = current->left; free(current); return node; /* returns the left child */ } else /* replace current->val with the value of the leftmost descendant of the right child */ current->val = _leftMost(current->right); current->right = _removeLeftmost(current->right); else /* not found, so recursive call */ ... }

29 Remove Node struct Node *_removeNode(struct Node *current, TYPE e){ if (current->val == e) /* Found it, remove it */ ... else /* not found, so recursive call */ if( e < current->val) current->left = _removeNode(current->left, e); else current->right = _removeNode(current->right, e);

return current; }

30 Useful Routines: _leftMost

/*Returns value of leftmost child of current node*/

TYPE _leftMost(struct Node *current) {

while(current->left != 0)

current = current->left;

return current->val;

}

31 Useful Routines: _removeLeftmost

/* Removes the leftmost descendant of current */ struct Node *_removeLeftmost(struct Node *current) { struct Node *temp; if(current->left != 0){ current->left = _removeLeftmost(current->left); return current; } temp = current->right; free(current); return temp; } 32 Complexity • Running down a path from root to leaf

• What is the time complexity? O( ?? )

33