van emde boas trees
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)