van emde boas trees

Post on 13-Apr-2017

72 Views

Category:

Education

13 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Advanced Algorithms – COMS31900

van Emde Boas trees

Benjamin Sach

Dictionaries

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U , the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

In previous lectures we have focussed on solutions using Hashing

such that for any key there is at most one pair (key, value) in the dictionary.

Dictionaries

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U , the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

In previous lectures we have focussed on solutions using Hashing

such that for any key there is at most one pair (key, value) in the dictionary.

in particular. . .

Dictionaries

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U , the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

In previous lectures we have focussed on solutions using Hashing

such that for any key there is at most one pair (key, value) in the dictionary.

THEOREM

In the Cuckoo hashing scheme:

• Every lookup and every delete takes O(1) worst-case time,

• The space is O(n) where n is the number of keys stored

• An insert takes amortised expected O(1) time

in particular. . .

Dictionaries

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U , the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

In previous lectures we have focussed on solutions using Hashing

such that for any key there is at most one pair (key, value) in the dictionary.

What’s not to like?

THEOREM

In the Cuckoo hashing scheme:

• Every lookup and every delete takes O(1) worst-case time,

• The space is O(n) where n is the number of keys stored

• An insert takes amortised expected O(1) time

in particular. . .

Dictionaries

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U , the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

In previous lectures we have focussed on solutions using Hashing

such that for any key there is at most one pair (key, value) in the dictionary.

What’s not to like?

THEOREM

In the Cuckoo hashing scheme:

• Every lookup and every delete takes O(1) worst-case time,

• The space is O(n) where n is the number of keys stored

• An insert takes amortised expected O(1) time

in particular. . .

Except the randomness,

Dictionaries

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U , the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

In previous lectures we have focussed on solutions using Hashing

such that for any key there is at most one pair (key, value) in the dictionary.

What’s not to like?

THEOREM

In the Cuckoo hashing scheme:

• Every lookup and every delete takes O(1) worst-case time,

• The space is O(n) where n is the number of keys stored

• An insert takes amortised expected O(1) time

in particular. . .

Except the randomness, the amortisation,

Dictionaries

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U , the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

In previous lectures we have focussed on solutions using Hashing

such that for any key there is at most one pair (key, value) in the dictionary.

What’s not to like?

THEOREM

In the Cuckoo hashing scheme:

• Every lookup and every delete takes O(1) worst-case time,

• The space is O(n) where n is the number of keys stored

• An insert takes amortised expected O(1) time

in particular. . .

Except the randomness, the amortisation, and the inflexibility

Dictionaries

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U , the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

In previous lectures we have focussed on solutions using Hashing

such that for any key there is at most one pair (key, value) in the dictionary.

What’s not to like?

THEOREM

In the Cuckoo hashing scheme:

• Every lookup and every delete takes O(1) worst-case time,

• The space is O(n) where n is the number of keys stored

• An insert takes amortised expected O(1) time

in particular. . .

Except the randomness, the amortisation, and the inflexibility

whatinflexibility?

Supporting more operations

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U - the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

such that for any key there is at most one pair (key, value) in the dictionary.

Supporting more operations

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U - the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

such that for any key there is at most one pair (key, value) in the dictionary.

What happens if we add more operations?

Supporting more operations

predecessor(k) - returns the (unique) element (x, v) in the dictionarywith the largest key, x such that x 6 k

We also want our data structure to support:

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U - the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

such that for any key there is at most one pair (key, value) in the dictionary.

What happens if we add more operations?

Supporting more operations

predecessor(k) - returns the (unique) element (x, v) in the dictionarywith the largest key, x such that x 6 k

We also want our data structure to support:

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U - the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

such that for any key there is at most one pair (key, value) in the dictionary.

What happens if we add more operations?

Supporting more operations

predecessor(k) - returns the (unique) element (x, v) in the dictionarywith the largest key, x such that x 6 k

We also want our data structure to support:

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U - the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

such that for any key there is at most one pair (key, value) in the dictionary.

What happens if we add more operations?

the universe

Supporting more operations

predecessor(k) - returns the (unique) element (x, v) in the dictionarywith the largest key, x such that x 6 k

We also want our data structure to support:

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U - the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

such that for any key there is at most one pair (key, value) in the dictionary.

What happens if we add more operations?

keys in the dictionary

the universe

Supporting more operations

predecessor(k) - returns the (unique) element (x, v) in the dictionarywith the largest key, x such that x 6 k

We also want our data structure to support:

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U - the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

such that for any key there is at most one pair (key, value) in the dictionary.

What happens if we add more operations?

Supporting more operations

predecessor(k) - returns the (unique) element (x, v) in the dictionarywith the largest key, x such that x 6 k

We also want our data structure to support:

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U - the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

such that for any key there is at most one pair (key, value) in the dictionary.

What happens if we add more operations?

k

Supporting more operations

predecessor(k) - returns the (unique) element (x, v) in the dictionarywith the largest key, x such that x 6 k

We also want our data structure to support:

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U - the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

such that for any key there is at most one pair (key, value) in the dictionary.

What happens if we add more operations?

k

predecessor(k)

Supporting more operations

predecessor(k) - returns the (unique) element (x, v) in the dictionarywith the largest key, x such that x 6 k

We also want our data structure to support:

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U - the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

such that for any key there is at most one pair (key, value) in the dictionary.

What happens if we add more operations?

successor(k) - returns the (unique) element (x, v) in the dictionarywith the smallest key, x such that x > k

k

predecessor(k)

Supporting more operations

predecessor(k) - returns the (unique) element (x, v) in the dictionarywith the largest key, x such that x 6 k

We also want our data structure to support:

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U - the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

such that for any key there is at most one pair (key, value) in the dictionary.

What happens if we add more operations?

successor(k) - returns the (unique) element (x, v) in the dictionarywith the smallest key, x such that x > k

k

successor(k)predecessor(k)

Supporting more operations

predecessor(k) - returns the (unique) element (x, v) in the dictionarywith the largest key, x such that x 6 k

We also want our data structure to support:

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U - the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

such that for any key there is at most one pair (key, value) in the dictionary.

What happens if we add more operations?

successor(k) - returns the (unique) element (x, v) in the dictionarywith the smallest key, x such that x > k

Supporting more operations

predecessor(k) - returns the (unique) element (x, v) in the dictionarywith the largest key, x such that x 6 k

We also want our data structure to support:

Three operations are supported:

In a dynamic dictionary data structure we store (key, value)-pairs

� add(x, v) Add the the pair (x, v) where x ∈ U - the universe

� lookup(x) Return v if (x, v) is in dictionary, or NULL otherwise.

� delete(x) Remove pair (x, v) (assuming (x, v) is in the dictionary).

such that for any key there is at most one pair (key, value) in the dictionary.

What happens if we add more operations?

successor(k) - returns the (unique) element (x, v) in the dictionarywith the smallest key, x such that x > k

These are very natural operations that the Hashing-based solutionsthat we have seen are very unsuited to

What could we use instead?

We could use a self-balancing binary search tree. . .like a 2-3-4 tree, a red-black tree or an AVL tree

4

52 58

51 53 5556 9

55 57

4 8

1 2 3 5 6 7 9

What could we use instead?

We could use a self-balancing binary search tree. . .like a 2-3-4 tree, a red-black tree or an AVL tree

All three of these data structures support:

add(x, v),lookup(x), delete(x),predecessor(k) and successor(k)

4

52 58

51 53 5556 9

55 57

4 8

1 2 3 5 6 7 9

What could we use instead?

We could use a self-balancing binary search tree. . .like a 2-3-4 tree, a red-black tree or an AVL tree

All three of these data structures support:

add(x, v),lookup(x), delete(x),predecessor(k) and successor(k)

each in O(logn) worst case time and O(n) space

4

52 58

51 53 5556 9

55 57

4 8

1 2 3 5 6 7 9

What could we use instead?

We could use a self-balancing binary search tree. . .like a 2-3-4 tree, a red-black tree or an AVL tree

All three of these data structures support:

add(x, v),lookup(x), delete(x),predecessor(k) and successor(k)

each in O(logn) worst case time and O(n) space

where n is the number of elements stored

4

52 58

51 53 5556 9

55 57

4 8

1 2 3 5 6 7 9

What could we use instead?

We could use a self-balancing binary search tree. . .like a 2-3-4 tree, a red-black tree or an AVL tree

All three of these data structures support:

add(x, v),lookup(x), delete(x),predecessor(k) and successor(k)

each in O(logn) worst case time and O(n) space

where n is the number of elements storedthey are also deterministic

4

52 58

51 53 5556 9

55 57

4 8

1 2 3 5 6 7 9

van Emde Boas Trees

Five operations will be supported:

In this lecture, we will see the van Emde Boas (vEB) tree

� add(x) Insert the integer x into S (where x ∈ U )

� lookup(x) Return yes if x is in S, or no otherwise.

� delete(x) Remove x from S

which stores a set S of integer keys from a universe U = {1, 2, 3, 4 . . . u} (i.e. u = |U |).

predecessor(k) Return the largest integer x in S such that x 6 k

successor(k) Return the smallest integer x in S such that x > k

k

successor(k)predecessor(k)

1 2 3 4 . . . u

van Emde Boas Trees

Five operations will be supported:

In this lecture, we will see the van Emde Boas (vEB) tree

� add(x) Insert the integer x into S (where x ∈ U )

� lookup(x) Return yes if x is in S, or no otherwise.

� delete(x) Remove x from S

which stores a set S of integer keys from a universe U = {1, 2, 3, 4 . . . u} (i.e. u = |U |).

predecessor(k) Return the largest integer x in S such that x 6 k

successor(k) Return the smallest integer x in S such that x > k

Warning: As stated the operations do not store any data (values) with the integers (keys)

k

successor(k)predecessor(k)

1 2 3 4 . . . u

van Emde Boas Trees

Five operations will be supported:

In this lecture, we will see the van Emde Boas (vEB) tree

� add(x) Insert the integer x into S (where x ∈ U )

� lookup(x) Return yes if x is in S, or no otherwise.

� delete(x) Remove x from S

which stores a set S of integer keys from a universe U = {1, 2, 3, 4 . . . u} (i.e. u = |U |).

predecessor(k) Return the largest integer x in S such that x 6 k

successor(k) Return the smallest integer x in S such that x > k

Warning: As stated the operations do not store any data (values) with the integers (keys)

It is straightforward to extend the van Emde Boas tree to store (key, value) pairswhen the keys are integers from U

k

successor(k)predecessor(k)

1 2 3 4 . . . u

van Emde Boas Trees

Five operations will be supported:

In this lecture, we will see the van Emde Boas (vEB) tree

� add(x) Insert the integer x into S (where x ∈ U )

� lookup(x) Return yes if x is in S, or no otherwise.

� delete(x) Remove x from S

which stores a set S of integer keys from a universe U = {1, 2, 3, 4 . . . u} (i.e. u = |U |).

predecessor(k) Return the largest integer x in S such that x 6 k

successor(k) Return the smallest integer x in S such that x > k

Warning: As stated the operations do not store any data (values) with the integers (keys)

It is straightforward to extend the van Emde Boas tree to store (key, value) pairswhen the keys are integers from U

k

successor(k)predecessor(k)

1 2 3 4 . . . u

(but I think it’s easier to think about like this)

van Emde Boas Trees

Five operations will be supported:

In this lecture, we will see the van Emde Boas (vEB) tree

� add(x) Insert the integer x into S (where x ∈ U )

� lookup(x) Return yes if x is in S, or no otherwise.

� delete(x) Remove x from S

which stores a set S of integer keys from a universe U = {1, 2, 3, 4 . . . u} (i.e. u = |U |).

predecessor(k) Return the largest integer x in S such that x 6 k

successor(k) Return the smallest integer x in S such that x > k

k

successor(k)predecessor(k)

1 2 3 4 . . . u

van Emde Boas Trees

Five operations will be supported:

In this lecture, we will see the van Emde Boas (vEB) tree

� add(x) Insert the integer x into S (where x ∈ U )

� lookup(x) Return yes if x is in S, or no otherwise.

� delete(x) Remove x from S

which stores a set S of integer keys from a universe U = {1, 2, 3, 4 . . . u} (i.e. u = |U |).

predecessor(k) Return the largest integer x in S such that x 6 k

successor(k) Return the smallest integer x in S such that x > k

k

successor(k)predecessor(k)

1 2 3 4 . . . u

All operations will take O(log log u) worst case time

and the space used is O(u)

van Emde Boas Trees

Five operations will be supported:

In this lecture, we will see the van Emde Boas (vEB) tree

� add(x) Insert the integer x into S (where x ∈ U )

� lookup(x) Return yes if x is in S, or no otherwise.

� delete(x) Remove x from S

which stores a set S of integer keys from a universe U = {1, 2, 3, 4 . . . u} (i.e. u = |U |).

predecessor(k) Return the largest integer x in S such that x 6 k

successor(k) Return the smallest integer x in S such that x > k

k

successor(k)predecessor(k)

1 2 3 4 . . . u

All operations will take O(log log u) worst case time

and the space used is O(u)

and it is a deterministic data structure

van Emde Boas Trees

Five operations will be supported:

In this lecture, we will see the van Emde Boas (vEB) tree

� add(x) Insert the integer x into S (where x ∈ U )

� lookup(x) Return yes if x is in S, or no otherwise.

� delete(x) Remove x from S

which stores a set S of integer keys from a universe U = {1, 2, 3, 4 . . . u} (i.e. u = |U |).

predecessor(k) Return the largest integer x in S such that x 6 k

successor(k) Return the smallest integer x in S such that x > k

k

successor(k)predecessor(k)

1 2 3 4 . . . u

All operations will take O(log log u) worst case time

and the space used is O(u)

and it is a deterministic data structure

Example: If U = {1, 2, 3, 4 . . . 100 · n}, you get O(log logn) time and O(n) space

van Emde Boas Trees

Five operations will be supported:

In this lecture, we will see the van Emde Boas (vEB) tree

� add(x) Insert the integer x into S (where x ∈ U )

� lookup(x) Return yes if x is in S, or no otherwise.

� delete(x) Remove x from S

which stores a set S of integer keys from a universe U = {1, 2, 3, 4 . . . u} (i.e. u = |U |).

predecessor(k) Return the largest integer x in S such that x 6 k

successor(k) Return the smallest integer x in S such that x > k

k

successor(k)predecessor(k)

1 2 3 4 . . . u

All operations will take O(log log u) worst case time

and the space used is O(u)

and it is a deterministic data structure

Example: If U = {1, 2, 3, 4 . . . n2}, you get O(log logn) time and O(n2) space

van Emde Boas Trees

Five operations will be supported:

In this lecture, we will see the van Emde Boas (vEB) tree

� add(x) Insert the integer x into S (where x ∈ U )

� lookup(x) Return yes if x is in S, or no otherwise.

� delete(x) Remove x from S

which stores a set S of integer keys from a universe U = {1, 2, 3, 4 . . . u} (i.e. u = |U |).

predecessor(k) Return the largest integer x in S such that x 6 k

successor(k) Return the smallest integer x in S such that x > k

k

successor(k)predecessor(k)

1 2 3 4 . . . u

All operations will take O(log log u) worst case time

and the space used is O(u)

and it is a deterministic data structure

Example: If U = {1, 2, 3, 4 . . . n3}, you get O(log logn) time and O(n3) space

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

add(12)

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

add(12)

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

add(12)

1

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1

delete(14)

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1

delete(14)

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1

delete(14)

0

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1 0

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1 0

lookup(11)

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1 0

lookup(11)

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1 0

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1 0

. . . looks good so far!

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1 0

. . . looks good so far!

What about the predecessor operation?

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1 0

. . . looks good so far!

What about the predecessor operation?

predecessor(11)

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1 0

. . . looks good so far!

What about the predecessor operation?

predecessor(11)

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1 0

. . . looks good so far!

What about the predecessor operation?

predecessor(11)

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1 0

. . . looks good so far!

predecessor(11)

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1 0

. . . looks good so far!

predecessor(11)

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1 0

. . . looks good so far!

predecessor(11)

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1 0

. . . looks good so far!

predecessor(11)

The predecessor and successor operations take O(u) time

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1 0

. . . looks good so far!

The predecessor and successor operations take O(u) time

Attempt 1: a big array

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

Build an array of length u. . .

A[i] = 1 iff i is in S

The operations add, delete and lookup all take O(1) time.

1 0

. . . looks good so far!

The predecessor and successor operations take O(u) time. . . not so good!

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

1 0

Attempt 2: a constant height tree(on top of a big array)

Split A into√u blocks each containing

√u bits

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

00 1 1 1 1 0 1 0 0 0 0 0 0 1 1AA

u

1 0

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

Split A into√u blocks each containing

√u bits

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

C

Split A into√u blocks each containing

√u bits

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

lookup(12)

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

lookup(12)

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

add(9)

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

add(9)

1

1

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

add(9)

1

1

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

1

1

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

delete(7)

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

delete(7)

0

?

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

delete(7)

0

?

to determine this bityou have to look through this block

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

delete(7)

0 00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0 00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0

delete(9)

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0

delete(9)

0

0?

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0

delete(9)

0

0?

to determine this bityou have to look through this block

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0 0

0

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0 0

0

predecessor(14)

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0 0

0

predecessor(14)

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0 0

0

predecessor(14)

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0 0

0

predecessor(14)

1

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0 0

0

predecessor(14)

1

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0 0

0

predecessor(14)

1

00

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0 0

0

predecessor(14)

1

0

1

0

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0 0

0

predecessor(14)

1

0

1

0

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0 0

0

predecessor(14)

1

0

1

0

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0 0

0

predecessor(14)

1

0

1

0

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0 0

0

predecessor(14)

1

0

1

1 0

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0 0

0

predecessor(14)

1

0

1

1 0

In the worst case we look atall of C and all of two blocks

Attempt 2: a constant height tree(on top of a big array)

161 2 3 4 5 6 7 8 9 10 11 12 13 14 15

AA

u

0 00 1 1 1 1 0 1 0 0 0 1

√u u

√u u

√u u

√u

0

01 1 1

√u

this is 1 ifany bit in the child block is 1

C

Split A into√u blocks each containing

√u bits

C is called thesummary of A

The lookup and add operations take O(1) time.

The operations delete, predecessor and successor take O(√u) time.

1

1

0 0

0

predecessor(14)

1

0

1

1 0

In the worst case we look atall of C and all of two blocks

(successor is the same)

An abstract view

u

Split the universe U into√u blocks each associated with

√u elements

1 2 3 4 . . . u

there is a whole lotmore universe in here

An abstract view

u

√u u

√u u

√u u

√u

Split the universe U into√u blocks each associated with

√u elements

1 2 3 4 . . . u

there is a whole lotmore universe in here

An abstract view

u

√u u

√u u

√u u

√u

Split the universe U into√u blocks each associated with

√u elements

there is a whole lotmore universe in here

An abstract view

u

√u u

√u u

√u u

√u

Split the universe U into√u blocks each associated with

√u elements

there is a whole lotmore universe in here

we can think of each blockas a ‘little’ universe of size

√u

An abstract view

u

√u u

√u u

√u u

√u

Split the universe U into√u blocks each associated with

√u elements

we can think of each blockas a ‘little’ universe of size

√u

An abstract view

u

√u u

√u u

√u u

√u

Split the universe U into√u blocks each associated with

√u elements

we can think of each blockas a ‘little’ universe of size

√u

For block i, we build a data structure B[i]

which stores elements from {1, 2, 3, . . .√u}

An abstract view

u

√u u

√u u

√u u

√u

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

we can think of each blockas a ‘little’ universe of size

√u

For block i, we build a data structure B[i]

which stores elements from {1, 2, 3, . . .√u}

An abstract view

u

√u u

√u u

√u u

√u

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

we can think of each blockas a ‘little’ universe of size

√u

For block i, we build a data structure B[i]

which stores elements from {1, 2, 3, . . .√u}

x is stored in B[i] iff(x+ (i− 1)

√u)∈ S

An abstract view

u

√u u

√u u

√u u

√u

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

we can think of each blockas a ‘little’ universe of size

√u

For block i, we build a data structure B[i]

which stores elements from {1, 2, 3, . . .√u}

x is stored in B[i] iff(x+ (i− 1)

√u)∈ S

(this is just to deal with the offset from the start of the real universe)

An abstract view

u

√u u

√u u

√u u

√u

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

For block i, we build a data structure B[i]

which stores elements from {1, 2, 3, . . .√u}

x is stored in B[i] iff(x+ (i− 1)

√u)∈ S

(this is just to deal with the offset from the start of the real universe)

An abstract view

u

√u u

√u u

√u u

√u

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

For block i, we build a data structure B[i]

which stores elements from {1, 2, 3, . . .√u}

x is stored in B[i] iff(x+ (i− 1)

√u)∈ S

An abstract view

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

For block i, we build a data structure B[i]

which stores elements from {1, 2, 3, . . .√u}

We also build a summary data structure C

x is stored in B[i] iff(x+ (i− 1)

√u)∈ S

which stores elements from {1, 2, 3, . . .√u}

i is stored in C iff B[i] is non-empty

An abstract view

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

For block i, we build a data structure B[i]

which stores elements from {1, 2, 3, . . .√u}

We also build a summary data structure C

x is stored in B[i] iff(x+ (i− 1)

√u)∈ S

which stores elements from {1, 2, 3, . . .√u}

i is stored in C iff B[i] is non-empty

An abstract view

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

How should we build B[1], B[2], . . . B[√u] and C?

An abstract view

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

How should we build B[1], B[2], . . . B[√u] and C?

Recursion!

An abstract view

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

How should we build B[1], B[2], . . . B[√u] and C?

Recursion!

Each B[i] has universe {1, 2, 3, . . .√u}

An abstract view

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

How should we build B[1], B[2], . . . B[√u] and C?

Recursion!

Each B[i] has universe {1, 2, 3, . . .√u}

We recursively split this into 4√u blocks each associated with 4

√u elements. . .

An abstract view

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

How should we build B[1], B[2], . . . B[√u] and C?

Recursion!

Each B[i] has universe {1, 2, 3, . . .√u}

We recursively split this into 4√u blocks each associated with 4

√u elements. . .

eventually (after some more work), this will lead to an O(log logn) time solution

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

Attempt 3: Recursion

How do we perform the operations?

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

Attempt 3: Recursion

To perform add(x):

Step 1 Determine which B[i] the element x belongs in(this takes O(1) time with a little bit twiddling)

Step 3 add x to B[i](suitably adjusting the offset from the start of B[i])

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

Attempt 3: Recursion

To perform add(x):

Step 1 Determine which B[i] the element x belongs in(this takes O(1) time with a little bit twiddling)

Step 3 add x to B[i](suitably adjusting the offset from the start of B[i])

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

x

Attempt 3: Recursion

To perform add(x):

Step 1 Determine which B[i] the element x belongs in(this takes O(1) time with a little bit twiddling)

Step 3 add x to B[i](suitably adjusting the offset from the start of B[i])

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

x

Attempt 3: Recursion

To perform add(x):

Step 1 Determine which B[i] the element x belongs in(this takes O(1) time with a little bit twiddling)

Step 3 add x to B[i](suitably adjusting the offset from the start of B[i])

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

x

Attempt 3: Recursion

To perform add(x):

Step 1 Determine which B[i] the element x belongs in(this takes O(1) time with a little bit twiddling)

Step 3 add x to B[i](suitably adjusting the offset from the start of B[i])

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

x

Attempt 3: Recursion

To perform add(x):

Step 1 Determine which B[i] the element x belongs in(this takes O(1) time with a little bit twiddling)

Step 3 add x to B[i](suitably adjusting the offset from the start of B[i])

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

x

Attempt 3: Recursion

To perform add(x):

Step 1 Determine which B[i] the element x belongs in(this takes O(1) time with a little bit twiddling)

Step 3 add x to B[i](suitably adjusting the offset from the start of B[i])

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

x

We actually insert x′ where

x =(x′ + (i− 1)

√u)

Attempt 3: Recursion

To perform add(x):

Step 1 Determine which B[i] the element x belongs in(this takes O(1) time with a little bit twiddling)

Step 3 add x to B[i](suitably adjusting the offset from the start of B[i])

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

x

Attempt 3: Recursion

To perform add(x):

Step 1 Determine which B[i] the element x belongs in(this takes O(1) time with a little bit twiddling)

Step 3 add x to B[i](suitably adjusting the offset from the start of B[i])

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Compute the predecessor of x in B[j]

(suitably adjusting the offset from the start of B[j])

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

(suitably adjusting the offset from the start of B[i])

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Compute the predecessor of x in B[j]

(suitably adjusting the offset from the start of B[j])

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

(suitably adjusting the offset from the start of B[i])

x

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Compute the predecessor of x in B[j]

(suitably adjusting the offset from the start of B[j])

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

(suitably adjusting the offset from the start of B[i])

x

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Compute the predecessor of x in B[j]

(suitably adjusting the offset from the start of B[j])

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

(suitably adjusting the offset from the start of B[i])

x

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Compute the predecessor of x in B[j]

(suitably adjusting the offset from the start of B[j])

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

(suitably adjusting the offset from the start of B[i])

x

done!

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Compute the predecessor of x in B[j]

(suitably adjusting the offset from the start of B[j])

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

(suitably adjusting the offset from the start of B[i])

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Compute the predecessor of x in B[j]

(suitably adjusting the offset from the start of B[j])

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

(suitably adjusting the offset from the start of B[i])

x

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Compute the predecessor of x in B[j]

(suitably adjusting the offset from the start of B[j])

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

(suitably adjusting the offset from the start of B[i])

x

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Compute the predecessor of x in B[j]

(suitably adjusting the offset from the start of B[j])

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

(suitably adjusting the offset from the start of B[i])

x

x has no predecessor in here

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Compute the predecessor of x in B[j]

(suitably adjusting the offset from the start of B[j])

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

(suitably adjusting the offset from the start of B[i])

x

x has no predecessor in herei

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Compute the predecessor of x in B[j]

(suitably adjusting the offset from the start of B[j])

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

(suitably adjusting the offset from the start of B[i])

x

x has no predecessor in hereij = 2

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Compute the predecessor of x in B[j]

(suitably adjusting the offset from the start of B[j])

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

(suitably adjusting the offset from the start of B[i])

x

x has no predecessor in hereij = 2

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Compute the predecessor of x in B[j]

(suitably adjusting the offset from the start of B[j])

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

(suitably adjusting the offset from the start of B[i])

x

x has no predecessor in hereij = 2

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

The operations lookup, delete and successor canall also be defined in a similar, recursive manner

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

The operations lookup, delete and successor canall also be defined in a similar, recursive manner

How efficient are the operations?

Attempt 3: Recursion

To perform add(x):

Step 1 Determine which B[i] the element x belongs in(this takes O(1) time with a little bit twiddling)

Step 3 add x to B[i](suitably adjusting the offset from the start of B[i])

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

Attempt 3: Recursion

To perform add(x):

Step 1 Determine which B[i] the element x belongs in(this takes O(1) time with a little bit twiddling)

Step 3 add x to B[i](suitably adjusting the offset from the start of B[i])

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

up to two recursivecalls

add makes

Attempt 3: Recursion

To perform add(x):

Step 1 Determine which B[i] the element x belongs in(this takes O(1) time with a little bit twiddling)

Step 3 add x to B[i](suitably adjusting the offset from the start of B[i])

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

up to two recursivecalls

add makes

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Compute the predecessor of x in B[j]

(suitably adjusting the offset from the start of B[j])

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

(suitably adjusting the offset from the start of B[i])

up to three recursivecalls!

predecessor makes

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

The operations lookup, delete and successor canall also be defined in a similar, recursive manner

How efficient are the operations?

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

The operations lookup, delete and successor canall also be defined in a similar, recursive manner

How efficient are the operations?

The add operation makes up to two recursive callsand the predecessor operation makes up to three

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

The operations lookup, delete and successor canall also be defined in a similar, recursive manner

How efficient are the operations?

The add operation makes up to two recursive callsand the predecessor operation makes up to three

Each recursive call could in turn make multiple recursive calls. . .

Attempt 3: Recursion

u

√u u

√u u

√u u

√u

√u

C

Split the universe U into√u blocks each associated with

√u elements

B[1] B[2] B[3] B[√

u]

The operations lookup, delete and successor canall also be defined in a similar, recursive manner

How efficient are the operations?

The add operation makes up to two recursive callsand the predecessor operation makes up to three

Each recursive call could in turn make multiple recursive calls. . .

this could get out of hand!

A closer look at predecessor

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Return the predecessor of x in B[j]

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

x

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

A closer look at predecessor

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Return the predecessor of x in B[j]

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

x

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

Observation 1: if x has a predecessor in B[i] we only make one recursive call

A closer look at predecessor

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Return the predecessor of x in B[j]

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

x

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

Observation 1: if x has a predecessor in B[i] we only make one recursive call

x has a predecessor in B[i] iffx > the minimum in B[i]

A closer look at predecessor

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Return the predecessor of x in B[j]

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

Step 3 If x has no predecessor in B[i]:

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

Observation 1: if x has a predecessor in B[i] we only make one recursive call

x has a predecessor in B[i] iffx > the minimum in B[i]

x

A closer look at predecessor

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Return the predecessor of x in B[j]

Compute j = predecessor(i) in C

Step 2 Compute the predecessor of x in B[i]

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

Observation 1: if x has a predecessor in B[i] we only make one recursive call

x has a predecessor in B[i] iffx > the minimum in B[i]

x

Step 3 If x < the minimum in B[i]:

A closer look at predecessor

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Return the predecessor of x in B[j]

Compute j = predecessor(i) in C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

Observation 1: if x has a predecessor in B[i] we only make one recursive call

x has a predecessor in B[i] iffx > the minimum in B[i]

x

Step 3 If x < the minimum in B[i]:

Return the predecessor of x in B[i]

Step 2 If x > the minimum in B[i]:

A closer look at predecessor

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Return the predecessor of x in B[j]

Compute j = predecessor(i) in C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

Observation 1: if x has a predecessor in B[i] we only make one recursive call

x has a predecessor in B[i] iffx > the minimum in B[i]

x

Step 3 If x < the minimum in B[i]:

Return the predecessor of x in B[i]

Step 2 If x > the minimum in B[i]:

Now we make at mosttwo recursive calls

A closer look at predecessor

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Return the predecessor of x in B[j]

Compute j = predecessor(i) in C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

Observation 1: if x has a predecessor in B[i] we only make one recursive call

x has a predecessor in B[i] iffx > the minimum in B[i]

x

Step 3 If x < the minimum in B[i]:

Return the predecessor of x in B[i]

Step 2 If x > the minimum in B[i]:

Now we make at mosttwo recursive calls

(ignoring finding the minimum)

A closer look at predecessor

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Return the predecessor of x in B[j]

Compute j = predecessor(i) in C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

x

Step 3 If x < the minimum in B[i]:

Return the predecessor of x in B[i]

Step 2 If x > the minimum in B[i]:

A closer look at predecessor

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Return the predecessor of x in B[j]

Compute j = predecessor(i) in C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

x

Step 3 If x < the minimum in B[i]:

Return the predecessor of x in B[i]

Step 2 If x > the minimum in B[i]:we need to get rid

of one of theserecursive calls

A closer look at predecessor

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Return the predecessor of x in B[j]

Compute j = predecessor(i) in C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

x

Step 3 If x < the minimum in B[i]:

Return the predecessor of x in B[i]

Step 2 If x > the minimum in B[i]:

ij = 2

we need to get ridof one of these

recursive calls

A closer look at predecessor

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Return the predecessor of x in B[j]

Compute j = predecessor(i) in C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

x

Step 3 If x < the minimum in B[i]:

Return the predecessor of x in B[i]

Step 2 If x > the minimum in B[i]:

Observation 2: In Step 3, the predecessor of x in B[j] is the maximum in B[j]

ij = 2

we need to get ridof one of these

recursive calls

A closer look at predecessor

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Return the predecessor of x in B[j]

Compute j = predecessor(i) in C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

x

Step 3 If x < the minimum in B[i]:

Return the predecessor of x in B[i]

Step 2 If x > the minimum in B[i]:

Observation 2: In Step 3, the predecessor of x in B[j] is the maximum in B[j]

ij = 2

A closer look at predecessor

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Compute j = predecessor(i) in C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

x

Step 3 If x < the minimum in B[i]:

Return the predecessor of x in B[i]

Step 2 If x > the minimum in B[i]:

Observation 2: In Step 3, the predecessor of x in B[j] is the maximum in B[j]

ij = 2

Return the maximum in B[j]

A closer look at predecessor

To perform predecessor(x):

Step 1 Determine which B[i] the element x belongs in

Compute j = predecessor(i) in C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

x

Step 3 If x < the minimum in B[i]:

Return the predecessor of x in B[i]

Step 2 If x > the minimum in B[i]:

Observation 2: In Step 3, the predecessor of x in B[j] is the maximum in B[j]

ij = 2

Return the maximum in B[j]

Now we make exactlyone recursive call

(ignoring finding the min/max)

Finally: van Emde Boas Trees

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

So that we can find the min/max quickly we store them seperately. . .

Finally: van Emde Boas Trees

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

So that we can find the min/max quickly we store them seperately. . .

Finally: van Emde Boas Trees

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

So that we can find the min/max quickly we store them seperately. . .

Remember that each B[i] and C are also vEB (van Emde Boas) treeseach over the universe {1, 2, 3, . . .

√u}

Finally: van Emde Boas Trees

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

So that we can find the min/max quickly we store them seperately. . .

Remember that each B[i] and C are also vEB (van Emde Boas) treeseach over the universe {1, 2, 3, . . .

√u}

In particular B[i] also stores it’s min/max elements seperatelyso recovering the minimum or maximum in B[i] (or C) takes O(1) time

Finally: van Emde Boas Trees

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

So that we can find the min/max quickly we store them seperately. . .

Remember that each B[i] and C are also vEB (van Emde Boas) treeseach over the universe {1, 2, 3, . . .

√u}

In particular B[i] also stores it’s min/max elements seperatelyso recovering the minimum or maximum in B[i] (or C) takes O(1) time

There is one more important thing, the minimum is not also stored in B[i]

Finally: van Emde Boas Trees

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

So that we can find the min/max quickly we store them seperately. . .

Remember that each B[i] and C are also vEB (van Emde Boas) treeseach over the universe {1, 2, 3, . . .

√u}

In particular B[i] also stores it’s min/max elements seperatelyso recovering the minimum or maximum in B[i] (or C) takes O(1) time

There is one more important thing, the minimum is not also stored in B[i]

Finally: van Emde Boas Trees

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

So that we can find the min/max quickly we store them seperately. . .

Remember that each B[i] and C are also vEB (van Emde Boas) treeseach over the universe {1, 2, 3, . . .

√u}

In particular B[i] also stores it’s min/max elements seperatelyso recovering the minimum or maximum in B[i] (or C) takes O(1) time

There is one more important thing, the minimum is not also stored in B[i]

the min isonly stored here

Finally: van Emde Boas Trees

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

So that we can find the min/max quickly we store them seperately. . .

Remember that each B[i] and C are also vEB (van Emde Boas) treeseach over the universe {1, 2, 3, . . .

√u}

In particular B[i] also stores it’s min/max elements seperatelyso recovering the minimum or maximum in B[i] (or C) takes O(1) time

There is one more important thing, the minimum is not also stored in B[i]

the min isonly stored here

this allows us to avoid making multiple recursive calls when adding an element

Another look at add

To perform add(x):

Step 1 Determine which B[i] the element x belongs in

Step 3 If B[i] is not empty, add x to B[i]

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

and set the min and max in B[i] to x (adjusting the offset)

Another look at add

To perform add(x):

Step 1 Determine which B[i] the element x belongs in

Step 3 If B[i] is not empty, add x to B[i]

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

x

and set the min and max in B[i] to x (adjusting the offset)

Another look at add

To perform add(x):

Step 1 Determine which B[i] the element x belongs in

Step 3 If B[i] is not empty, add x to B[i]

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

x

and set the min and max in B[i] to x (adjusting the offset)

one recursive callwe make

Another look at add

To perform add(x):

Step 1 Determine which B[i] the element x belongs in

Step 3 If B[i] is not empty, add x to B[i]

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

x

and set the min and max in B[i] to x (adjusting the offset)

one recursive callwe make

Another look at add

To perform add(x):

Step 1 Determine which B[i] the element x belongs in

Step 3 If B[i] is not empty, add x to B[i]

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

x

and set the min and max in B[i] to x (adjusting the offset)

Another look at add

To perform add(x):

Step 1 Determine which B[i] the element x belongs in

Step 3 If B[i] is not empty, add x to B[i]

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

and set the min and max in B[i] to x (adjusting the offset)

x

Another look at add

To perform add(x):

Step 1 Determine which B[i] the element x belongs in

Step 3 If B[i] is not empty, add x to B[i]

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

and set the min and max in B[i] to x (adjusting the offset)

x

one recursive callwe make

Another look at add

To perform add(x):

Step 1 Determine which B[i] the element x belongs in

Step 3 If B[i] is not empty, add x to B[i]

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

and set the min and max in B[i] to x (adjusting the offset)

x

one recursive callwe make

Another look at add

To perform add(x):

Step 1 Determine which B[i] the element x belongs in

Step 3 If B[i] is not empty, add x to B[i]

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

and set the min and max in B[i] to x (adjusting the offset)

x

one recursive callwe make

Another look at add

To perform add(x):

Step 1 Determine which B[i] the element x belongs in

Step 3 If B[i] is not empty, add x to B[i]

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

and set the min and max in B[i] to x (adjusting the offset)

x

one recursive callwe make

this is notrecursive

Another look at add

To perform add(x):

Step 1 Determine which B[i] the element x belongs in

Step 3 If B[i] is not empty, add x to B[i]

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

and set the min and max in B[i] to x (adjusting the offset)

x

one recursive callwe make

this is notrecursive

Another look at add

To perform add(x):

Step 1 Determine which B[i] the element x belongs in

Step 3 If B[i] is not empty, add x to B[i]

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

and set the min and max in B[i] to x (adjusting the offset)

Now we always make exactly one recursive call

Another look at add

To perform add(x):

Step 1 Determine which B[i] the element x belongs in

Step 3 If B[i] is not empty, add x to B[i]

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

and set the min and max in B[i] to x (adjusting the offset)

Now we always make exactly one recursive callbut what happens when the min/max change?

Another look at add

To perform add(x):

Step 1 Determine which B[i] the element x belongs in

Step 3 If B[i] is not empty, add x to B[i]

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

and set the min and max in B[i] to x (adjusting the offset)

Now we always make exactly one recursive callx

but what happens when the min/max change?

Another look at add

To perform add(x):

Step 1 Determine which B[i] the element x belongs in

Step 3 If B[i] is not empty, add x to B[i]

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

and set the min and max in B[i] to x (adjusting the offset)

Now we always make exactly one recursive callx

but what happens when the min/max change?

Another look at add

To perform add(x):

Step 1 Determine which B[i] the element x belongs in

Step 3 If B[i] is not empty, add x to B[i]

Step 2 If B[i] is empty, add i to C

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

and set the min and max in B[i] to x (adjusting the offset)

Now we always make exactly one recursive call

Step 0 If x < min then swap x and min

x

but what happens when the min/max change?

Step 4 Update the max

Time Complexity

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

Time Complexity

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

We have seen that the operations add and predecessor can be definedso that they make only one recursive call

Time Complexity

The operations lookup, delete and successor canall also be defined in a similar, recursive manner

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

We have seen that the operations add and predecessor can be definedso that they make only one recursive call

so that they make only one recursive call

Time Complexity

The operations lookup, delete and successor canall also be defined in a similar, recursive manner

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

We have seen that the operations add and predecessor can be definedso that they make only one recursive call

so that they make only one recursive call

How long do the operations take?

Time Complexity

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

Time Complexity

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

Let T (u) be the time complexity of the add operation(where u is the universe size)

Time Complexity

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

Let T (u) be the time complexity of the add operation

We have that, T (u) = T (√u)+O(1)

(where u is the universe size)

Time Complexity

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

Let T (u) be the time complexity of the add operation

We have that, T (u) = T (√u)+O(1)

Using substitution and the master method you can show that. . . T (u) = O(log log u)

(where u is the universe size)

Time Complexity

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

We have that, T (u) = T (√u)+O(1)

Using substitution and the master method you can show that. . . T (u) = O(log log u)

Let T (u) be the time complexity of the predecessor operation(where u is the universe size)

Time Complexity

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

We have that, T (u) = T (√u)+O(1)

Using substitution and the master method you can show that. . . T (u) = O(log log u)

Let T (u) be the time complexity of the predecessor operation(where u is the universe size)

this holds for all the operations

Space Complexity

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

Space Complexity

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

Let Z(u) be the space used by a vEB tree over a universe of size u

Space Complexity

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

Let Z(u) be the space used by a vEB tree over a universe of size u

We have that, Z(u) = (√u+ 1)·Z(

√u)+O(1)

Space Complexity

u

√u u

√u u

√u u

√u

√u

C

B[1] B[2] B[3] B[√

u]

min max

37 483

the min isonly stored here

Let Z(u) be the space used by a vEB tree over a universe of size u

We have that, Z(u) = (√u+ 1)·Z(

√u)+O(1)

If you solve this you get that. . . Z(u) = O(u)

van Emde Boas Trees

Five operations are supported:

The van Emde Boas (vEB) tree

� add(x) Insert the integer x into S (where x ∈ U )

� lookup(x) Return yes if x is in S, or no otherwise.

� delete(x) Remove x from S

stores a set S of integer keys from a universe U = {1, 2, 3, 4 . . . u} (i.e. u = |U |).

predecessor(k) Return the largest integer x in S such that x 6 k

successor(k) Return the smallest integer x in S such that x > k

k

successor(k)predecessor(k)

1 2 3 4 . . . u

All operations take O(log log u) worst case time

and the space used is O(u)

van Emde Boas Trees

Five operations are supported:

The van Emde Boas (vEB) tree

� add(x) Insert the integer x into S (where x ∈ U )

� lookup(x) Return yes if x is in S, or no otherwise.

� delete(x) Remove x from S

stores a set S of integer keys from a universe U = {1, 2, 3, 4 . . . u} (i.e. u = |U |).

predecessor(k) Return the largest integer x in S such that x 6 k

successor(k) Return the smallest integer x in S such that x > k

k

successor(k)predecessor(k)

1 2 3 4 . . . u

All operations take O(log log u) worst case time

and the space used is O(u)

The space can be improved to O(n) using hashing (see y-fast trees)

top related