binary search tree binary search tree 1 kabo's visualization

36
Binary Search Tree 1 Gnarly Trees: visualization system for tree algorithms, http ://people.ksp.sk/~kuko/bak/index.html try BST binary search tree (might take awhile to display). standalone app works better A random Binary Search Tree Binary Search Tree

Upload: others

Post on 03-Feb-2022

15 views

Category:

Documents


0 download

TRANSCRIPT

Binary Search Tree 1

Gnarly Trees: visualization system for tree algorithms,

http://people.ksp.sk/~kuko/bak/index.html

try BST binary search tree (might take awhile to display).

standalone app works better

A random Binary Search Tree

Binary Search Tree

Binary Search Tree 2traversal

BSTNode {

Integer key

BSTNode right, left;

BSTNode(Integer k){

key = k

right = null

left = null }

Integer get() {

return key }

int compareTo(...)

{...};

}

BSTNode root; // “n”...

inorder(BSTNode n) { // iterator

if (n == null) return;

inorder(n.left)

visit() // print?

inorder(n.right)

}

element

left right

n 32

v e

v 17

b g

e 41

u w

b 11

null null

g 23

null null

u 38

null null

w 42

null null

Write w/ generics <Element>

Change order of

“go left”

“visit”

“go right”

root

Binary Search Tree 3Binary Search Tree (BST)

Search Binary Tree to find a target node with specific <Element>

if key is in the list return a reference to the BSTNode

if key is not in the list return null

BSTNode find (Element target) { // public call

return find(root, target; } // private recursive call

BSTNode find(BSTNode current, Element target) {

if (current == null) return current; // empty list

int result = target.compareTo(current.get());

if (result == 0) // target == current

return current;

else if (result < 0) // target < current

return find(current.getLeft(), target);

else // target > 0

return find(current.getRight(), target);

}

Write this algorithm to work with your generic BSTNode<Element> ?

Write this algorithm with a while loop ?

Binary Search Tree 4BSTree <E>

Element is an example

class type for <E>

In application classprivate BSTree bst = new BSTree<Element>();

Binary Search Tree 5Full balanced BST

v 0

null null

p 3

null, n null

n 1

null, v null

v 0

null null

n 1

null,

v

null,

c

c 2

null null

v 0

null null

n 1

v c

c 2

null null

f 4

null null

u 5

f w

w 6

null null

p 3

n u

0 1 2 3 4 5 6

3

1 5

0 2 4 6

root

p

see BinaryPartitionArrayList.java

Binary Search Tree 6Balanced BST growth

height n leafs average log(n,2) difference ceil(log(n,2))

1 1 1 1.00 0.00 -1.000 0

2 3 2 1.67 1.58 -0.082 2

3 7 4 2.43 2.81 0.379 3

4 15 8 3.27 3.91 0.640 4

5 31 16 4.16 4.95 0.793 5

6 63 32 5.10 5.98 0.882 6

7 127 64 6.06 6.99 0.934 7

8 255 128 7.03 7.99 0.963 8

9 511 256 8.02 9.00 0.980 9

10 1,023 512 9.01 10.00 0.989 10

11 2,047 1,024 10.01 11.00 0.994 11

12 4,095 2,048 11.00 12.00 0.997 12

13 8,191 4,096 12.00 13.00 0.998 13

14 16,383 8,192 13.00 14.00 0.999 14

15 32,767 16,384 14.00 15.00 0.999 15

16 65,535 32,768 15.00 16.00 1.000 16

17 131,071 65,536 16.00 17.00 1.000 17

18 262,143 131,072 17.00 18.00 1.000 18

19 524,287 262,144 18.00 19.00 1.000 19

20 1,048,575 524,288 19.00 20.00 1.000 20

Binary Search Tree 7

-1.500

-1.000

-0.500

0.000

0.500

1.000

1.500

1 3 5 7 9 11 13 15 17 19 21 23 25

height

Binary Tree height

ceil( log(n,2)) - average

Binary Search Tree 8initial insertion example

n 32

v e

v 17

b null

g

e 41

u w

b 11

null null

u 38

null null

w 42

null null

root

Assume no duplicates allowed

insert (g ) // 23

C1 root

g < C1 && C1.left != null

T: C2 C1.left

g > C2 && C2.right != null

T: C3 C2.right

F: g > C2 && C2.right == null

T: C2.right g

done

insert (t ) // 7

C1

C2

g 23

null null

Binary Search Tree 92 insertion cases

Assumes no duplicate Elements allowed in BST

void insert (BSTNode newNode)

1. Empty tree

root == null && size == 0

root newNode

size 1

2. Non-empty tree // all insertions result in ordered search tree

current root

Search for insertion place // insertion is always at a leaf

newNode < current && current.left ! null ?

current current.left

newNode < current && current.left == null ?

current.left newNode

// 2 similar situations when newNode > current

size++

BST Recursive insert Binary Search Tree 10

Algorithms (insert and delete) adapted from C. Shaffer, Data Structures

& Algorithm Analysis in Java, 3rd edition, Dover, 2011.

BSTNode<E> insertR (BSTNode<E> node, BSTNode<E> newNode) {

if (node == null) return newNode; // at leaf

if (node.compareTo(newNode) > 0) // node.key >nNode.key

node.setLeft(insertR (node.left(), newNode)

else node.setRight(insertR (node.right(), newNode)

return node

}

initial call

bst.setRoot(insertR(bst.getRoot,

new BSTNode<E>( new E(key)) ))

insert: 3, 1, 0, 2, 5, 4, 6

Binary Search Tree 11trace of recursive insert

RBSTDemo run:

aBST: size = 0 root = null

insert [3,null,null] leaf root <-- 3

insert [1,null,null] 1<3 L leaf 3L <-- 1 root <-- 3

insert [0,null,null] 0<3 L 0<1 L leaf 1L <-- 0

3L <-- 1 root <-- 3

insert [2,null,null] 2<3 L 2>1 R || leaf 1R <-- 2

3L <-- 1 root <-- 3

insert [5,null,null] 5>3 R || leaf 3R <-- 5 root <-- 3

insert [4,null,null] 4>3 R || 4<5 L leaf 5L <-- 4

3R <-- 5 root <-- 3

insert [6,null,null] 6>3 R || 6>5 R || leaf 5R <-- 6

3R <-- 5 root <-- 3

aBST: size = 7 root = [3,1,5]

inorder: [0,null,null]3 [1,0,2]2 [2,null,null]3 [3,1,5]1

[4,null,null]3 [5,4,6]2 [6,null,null]3

Binary Search Tree 12initial deletion example

n 32

v e

e 41

u w

w 42

null null

root

delete (e ) // 41

C1 root

e > C1 && C1.right != null ?

T: C2 C1.right

C2 == e && C2.right != null ?

T: M C2

// find greater replacement

C3 C2

C3.right == null ?

T: replace M.<E> with C3.<E>

replace M.right with C3.right

Replacement with immediate

predecessor is an equivalent

alternative to immediate successor.

Notes will use successor.

n 32

v e

root

e 42

u null

C1 C2 M

C3

Binary Search Tree 137 deletion cases

Assumes no duplicate Elements allowed in BST

deletedNode BSTNode delete(BSTNode target)

BSTNode current, last, marked, temp;

initially current root, last null, marked null, temp null

1. Empty tree

root == null, size == 0,

return null

Find target, last current before current updated, mark for deletion

2. target is root, root only node in tree

root.left == null && root.right == null

root null

size --

return current

nullroot

root target

null null

current

nullroot

target

null null

current

Binary Search Tree 14case 3

3. target is root, no successor, has predecessor

root.right == null && root.left != null

root root.left

size --

return current

roottarget

null

value

? ?

current

roottarget

null

value

? ?

current

Binary Search Tree 15cases 4

4. target is a leaf has no successor && no predecessor

current.left == null && current.right == null

2 situations:

last < current : last.right null // shown below

last > current : last.left null // draw as an exercise

size --

return current

rootvaluei

target

null null

last

current

rootvaluei

null

target

null null

last

current

there can be many nodes between root and target

Binary Search Tree 16case 5

Mark target and search for immediate successor cases.

marked current

5. target's has a left, but no right (no successor) , propogate left up tree

2 situations:

last < current : last.right current.left

last > current : last.left current.left // shown

size --

return current

root

valuej

target

null

last

mark

valuei

current

root

valuej

target

? null

valuei

Binary Search Tree 17cases 6

target has a successor (cases 6 and 7)

last current, current current.right

6. target's immediate right has no left predecessor branch

current.left == null, current.right != null

copy marked into temp

copy current's value and left into marked

size --

last.right current.right, return temp

temp

target

root

targetlast

valuei

null

mark

current

valueilast

mark

Binary Search Tree 18case 7

7. target's immediate right has a left predecessor

that leads to an immediate successor.

copy marked into temp

copy current into marked

size --

last.left null

return temp

root

target

last

valuei

null null

mark

current

valuei

last

marktemp

target

valuej

null

BST Recursive delete

BSTNode<E> deleteR (BSTNode<E> node, BSTNode<E> target) {

if (node == null) return null; // halt, leaf not found

// find target

if (node.compareTo(target) > 0) // node.key > target.key

node.setLeft() = deleteR(node.getLeft(), target)

else if (node.compareTo(target) < 0) // n.key < t.key

node.setRight() = deleteR(node.getRight(), target)

else // found target

// only right child

if(node.getLeft() == null) return node.getRight();

else // two children

BSTNode<E> temp = getMinR(node.getRight())

node.set(temp.get()); // sets E

node.setRight(deleteMinR(node.getRight())

return node

}

Binary Search Tree 19

getMinR(…), deleteMinR(…)

BSTNode<E> getMinR (BSTNode<E> node) {

if (node.getLeft() == null) return node

return getMinR(node.getLeft();

}

BSTNode<E> deleteMinR (BSTNode<E> node) {

if (node.getLeft() == null) return node.getRight()

node.setLeft(deleteMinR(node.getLeft())

return node;

}

Binary Search Tree 20

trace recursive deleteBinary Search Tree 21

Tree 37

/ \

24 42

/ \

40 43

\ \

41 120

delete 42

[37,24,42], < 0 setR(n.R), [42,40,43], == found,

getMin(n.R), [43,null,120][43,null,120], halt GetMin <--

[43,null,120], replace w/ 43, R <-- DeleteMin(n.R),

[43,null,120], halt DeleteMin <-- [120,null,null],

Tree 37

/ \

24 43

/ \

40 120

\

41

Try to trace delete of 37

recursive Vs non-recursiveBinary Search Tree 22

Non recursive create delete re-insertbalanced 73.58 126.09 105.85random 95.22 131.76 109.79% difference 29% 4% 4%

Recursive create delete re-insertbalanced 84.87 153.84 129.93random 116.47 168.61 136.61% difference 37% 10% 5%

% Recursive > Non Recursive create delete re-insert

balanced 15% 22% 23%random 22% 28% 24%

Consider a BST simulation experiment recursive and non-recursive

implementations in Java. The experiment created either a random or a

balanced tree with 210-1 nodes, deleted 29-1 nodes, and then re-inserted

28-1 (half of the deleted) nodes.

The results are time in nanoseconds / operation.

Why is creation faster than

either delete or re-insert?

Why are delete and

re-insert about the same?

Why is recursion slower?

Binary Search Tree 23Duplicate keys

Walkthrough: create aBSTree // do operations below in order

insert: 3, 1, 0, 2, 5, 4, 6 // state the cases

delete: 0, 1, 3, 5, 6, 4, 2, 2 // state the cases

Consider a BST with duplicate key values

but <E> element's other values are different. (Each E is unique).

Duplicate collection holds all E elements that share "key"

ArrayList<E> size() <= store, unused "?i" allocations

SinglyLinkedList <E>

key

left

ArrayList<E>

right

key

left

SinglyLinkedList<E>

right

E0 E1 En... ?0 ?1 ?n...

E0 E1 En

Key V0 V1 ... Vn

<E>

Binary Search Tree 24Huffman codes

Frequency Symbol

47 " "46 E45 T44 043 142 2

...26 "25 '24 A23 O22 I

...5 K4 X3 J2 Q1 Z

Normal symbol encoding is fixed

length (unicode, utf16).

Symbols can be coded with variable

length codes assigned by their

relative requency.

Here is graph of relative frequncy

for English letters, digits, and

punctuation.

Huffman coding uses

relative frequency and

binary tree to assign

variable codes.

http://en.wikipedia.org/wiki/Letter_frequency

Binary Search Tree 25

Consider a more limited vocabulary and relative frequency

Vocabulary Vocabulary length

symbol A B C D E F G 16 bit fixed code = 112 bits

frequency 6 5 4 1 2 2 3 Huffman code = 21 bits

while (more than 1 parentless node)

select 2 parentless nodes with smallest weights (frequency)

(break ties arbitrarily)

create a new node as their parent,

its weight sum child weights

label branches of tree all non-leaf nodes

left branch '0', right branch '1'

symbol code is concatenation of edge labels (0 or 1)

on path from root to symbol.

Applied Data Structures with C++, P. Smith, Jones Bartlett, 2004, pp 291-295

D (1) E (2)

3

F (2) G (3)

5

C (4)B (5)A (6)

Symbol code is the traversal from root to symbol leaf

Decode string: from root traverse tree using current digit to leaf

100001101011

100 C

00 A

110 F

1011 E

1011111001010

??

Binary Search Tree 26

D (1) E (2)

3

F (2) G (3)

5

C (4)B (5)A (6)

7

11

12

23

0

0

0

0

0 0

1

1

1

1

11

Binary Search Tree 27expressions as grammar

Grammar rules

x | y means x or y

x y means x followed by y

<word> means instance of "word" that is defined

Algebraic expression can be written as grammars.

Assume only binary operators like a + 10, not unary like –t

<op> = + | - | * | /

<term> = <constant> | <variable>

in-fix expression use "( ...)" to indicate operator precedence

pre- and post- fix expressions do not require "( ... )" for precedence

in-fix pre-fix remove matching parens, replace first with <op>

in-fix post-fix remove matching parens, replace second with <op>

prefix expression = <op> <term> <term>

postfix expression = <term> <term> <op>

Binary Search Tree 28expression as parse tree

*

+ *

A B / G

- +

C D E F

Consider this "in-fix" expression:

(A + B) * ((C – D) / (E + F) * G)

Traversals:

pre-order (VLR)

* + A B * / - C D + E F G

post-order (LRV)

A B + C D – E F + / G * *

t1 A + B t2 C – D

t3 E + F t4 t2 / t3

t5 t4 * G t1 * t5

post-order is a "post-fix" evaluation

of a fully parenthesized "in-fix"

expression.

aka RPN (Reverse Polish Notation)

Build expression parse tree using a stack ADT, later course topic...

Binary Search Tree 29Heap, BST in ArrayList

BST – insertion and deletion

O(log n) to O(n) // balanced to list

Better if full and balanced ... if balanced consider array based heap

Heap is a tree with weak (partially sorted) ordering

Heap is empty or its root references its highest priority value and

whose subtrees are also heaps.

Heaps are complete binary trees O(log n)

ArrayList based implementationclass Heap {

ArrayList <T> item;

// assume <T> implements Comparable's compareTo(...)

// or change for Comparator's compare(...)

// assume following method to swap item[i], item[j]

public void swap(int i, int j);

Binary Search Tree 30Heap – insert

insert(<T> value) {

int current, parent;

item.add(value) // add appends at end of arraylist

current = item.size() - 1

parent = (current - 1) / 2

while (parent >= 0 && item.get(current) >

item.get(parent))

{

swap(current, parent)

current = parent

parent = (current -1) /2

}

}

insert 92, 37, 78, 19 // no swap all inserts at end

insert: 57 heap 92, 37, 78, 19, 57 swap(4, 1)

92, 57, 78, 19, 37

insert 98 heap 92, 57, 78, 19, 37, 98 swap(5, 2)

98, 57, 92, 19, 37, 78 swap(2, 0)

insert 29, 77, 68, 52 heap 98 77 92 68 52 78 29 19 57 37

Binary Search Tree 31

98

77 92

68 52 78 29

19 57 3757

52 37

19 29

After 10 insertion:

Heap 98, 77, 92, 68, 52, 78, 29, 19, 57, 37

After 5 deletions:

Heap 57, 52, 37, 19, 29

Binary Search Tree 32Heap – delete

delete() { // assume ! heap.isEmpty()

value = item.get(0) // root is first element

item.set(0) = item.get(size() -1) // replace w/ last

item.remove(size() – 1) // remove last item

rebuild(0) // rebuild sub-heaps

return value

}

Delete 98

Heap 37, 77, 92, 68, 52, 78, 29, 19, 57 swap (0, 2)

92, 77, 37, 68, 52, 78, 29, 19, 57 swap (2, 5)

92, 77, 78, 68, 52, 37, 29, 19, 57

Delete 92

heap 57, 77, 78, 68, 52, 37, 29, 19 swap (0, 2)

78, 77, 57, 68, 52, 37, 29, 19

Delete 78

heap 19, 77, 57, 68, 52, 37, 29 swap (0, 1)

77, 19, 57, 68, 52, 37, 29 swap (1, 3)77, 68, 57, 19, 52, 37, 29

Binary Search Tree 33

rebuild(int root) {

int child, rChild

child = 2 * root + 1

if (child < item.size()) { // root ! leaf

rChild = child + 1

if ( (rChild < item.size()) &&

item.get(rChild).compareTo(item.get(child)) > 0 )

child = rChild // child is largest sibling

if (item.get(child).compareTo(item.get(root)) > 0)

{

swap(root, child)

rebuild(child)

}

}

}

Heap – rebuild

Binary Search Tree 34JCF PriorityQueue

maxHeap has largest value priority order (smallest value is minHeap)

JCF PriorityQueue <T> is a minHeap implementation.

O(log n) – offer(Element), add(Element), poll(), remove()

O(n) – remove(Object), contains(Object)

O(1) – peek(), element(), size()

Binary Search Tree 35exercises

1. Modify an inorder recursive traversal to print the node's value and

height. The height is not stored in the node, but determined at traversal.

2. Perform the following operations sequentially on a BSTree that is

initially empty. This is an on-paper exercise.

insert 10, 4, 2, 20, 8, 9, 15, 13, 50

delete 20, 2, 50, 15, 10, 4

3. trace the recursive insert (insertR) and delete (deleteR) algorithms for

#2

4. Do the BST operations in 2 using the Gnarly trees visual simulation

program.

5. Write a non-recursive BST insert and deletion algorithm using

BSTree and BSTNode classes on slide 4 (you can omit Element).

Binary Search Tree 36

23

2

9

6 12

50

36

29

32

75

61

53 72

6. Design a “visit-by level” traversal. For the example tree the visitation

order is:

23, 2, 50, 9, 36, 75, 6,

12, 29, 61, 32, 53, 72

7. Write a recursive "descend" traversal to visit a BST's key values in

descending order (assume integer keys, or implementation of

Comparable).