Efficient Priority Queues

advertisement
Efficient Priority Queues
Presenter: Yulik Feldman
Based on works of P.Emde Boas and D.Knuth
1
Agenda
Background: the definition of priority queue.
The standard implementation of priority
queue: space O(n), time O(log n).
Working with integers: more efficient
implementation is possible. The draft
program: space O(n), time is O(log log n) for
most cases, but worst case is still O(log n).
The revised program: space O(n), time O(log
log n).
2
Priority Queue Definition
Represents a subset of a given set of
elements and provides the following
operations on it:
Size() – number of elements in the subset
 Min() – the smallest element in the subset
 Max() – the largest element in the subset
 Insert(X) – insert X into the subset
 Delete(X) – delete X from the subset

3
Priority Queue Definition
Successor(X) – the smallest element in
the subset that is greater than X
 Predecessor(X) – the largest element in
the subset that is less than X
 Some custom definitions also include a
number of other operations, such as
Empty(), Member(X), ExtractMin(),
ExtractMax().

4
Standard
Implementation
Usually, the priority queues are implemented
using some kind of a balanced tree, like AVL,
2-3 tree or binary heap.
These representations require O(n) space
and O(log n) time for the Insert, Delete,
Successor and Predecessor operations.
The Size, Min and Max are trivially done in
O(1) time.
5
Limitations of the
standard approach
The standard approach suffers from the
theoretical lower bound of O(log n)
processing time for the decision tree model of
order n.
However, if the universe is assumed to
consist of the integers {1, …, n} only, this
bound can be outwitted.
For example, it is known that n integers in
range {1, …, n} can be sorted in linear time.
6
Taking advantage of
integers
Assuming that the universe consists of the
integers in range {1,…,n}, let n = n1 * n2.
Define q(x) = x / n2, and r(x) = x mod n2.
We can build a representation from n1
priority queues of order n2, plus an additional
priority queue of order n1 to keep track of
which of the others are nonempty. Thus the
universe is made up of n1 “galaxies” of
smaller universes.
7
The recursive
construction
The universe: a single
PQ of order n1
The galaxies: n1 PQs of
order n2
Each galaxy is subsequently split to sub-galaxies
8
Implementation: data
members
Class CPriorityQueue
{
int nSize; // size of the subset
int nLeast; // the smallest element
int nGreatest; // the largest element
PriorityQueue* pT; // a queue of order n1 for the
nonempty
galaxies
PriorityQueue* pG[n1-1]; // n1 queues of order n2 for the
galaxies
… Functions follow …
}
9
Initialization and trivial
functions
CPriorityQueue(int nOrder)
{
nSize = 0;
nLeast = MAXINT;
nGreatest = MININT;
pT = new CPriorityQueue(n1);
for (I = 0; I < n1; I++)
pG[I] = new CPriorityQueue(n2);
}
Size() { return nSize; }
Min() { return nLeast; }
Max() { return nGreatest; }
10
Insertion
Insert(int X)
{
nSize++;
if (X < nLeast)
nLeast = X;
if (X > nGreatest)
nGreatest = X;
if (pG[q(X)]->Size() == 0)
pT->Insert(q(x));
pG[q(X)]->Insert(r(X));
}
11
Deletion
Delete(int X)
{
nSize--;
pG[q(X)]->Delete(r(X));
if (pG[q(X)]->nSize == 0)
pT->Delete(q(X));
if (nSize == 0) {
nLeast = MAXINT;
nGreatest = MININT;
} else {
nLeast = pG[pT->Min()]->Min() + n2 * pT->Min();
nGreatest = pG[pT->Min()]->Max() + n2 * pT->Max();
}
}
12
Finding
successor/predecessor
Successor(int X)
{
if (r(X) > pG[q(X)]->Max())
return (pG[pT->Successor(q(X))]->Min() +
n2 * pT->Successor(q(X)))
else
return (pG[q(X)]->Successor(r(X)) +
n2 * q(x));
}
13
Time complexity
The time for Size(), Min() and Max() is
O(1).
For Insert(), T(n) = O(1) + T(n2) + (if
trivial n2 insertion then T(n1))
For Delete(), T(n) = O(1) + T(n2) + (if
trivial n2 deletion then T(n1))
For Successor(), T(n) <= O(1) +
max(T(n1), T(n2))
14
Time complexity (cont.)
We get best performance by taking n1 =
n2 = sqrt(n).
The solution to the recurrence T(n) =
2T(sqrt(n)) + O(1) has T(n) = log n,
while the solution to T(n) = T(sqrt(n)) +
O(1) has T(n) = log log n, hence for best
asymptotic growth we should try to
improve the algorithm.
15
Improving the algorithm
We should ensure that the trivial
insertions and deletions always take
O(1) time. The tricky thing is that trivial
deletions don’t have time to clean up
the data structure, and trivial insertions
haven’t the time to reinitialize it. We
solve it in the following way: whenever
nSize <= 1, the galaxies are not used
and all subsidiary queues will be empty.
16
The revised insertion
Everything is the same as before, except that
the implementation of Insert(), Delete() and
Successor() is changed as follows:
Insert(int X) {
if (nSize == 0) {
nSize=1;
nLeast = X;
nGreatest = X;
}
else {
…
nSize = 0
optimization
17
The revised insertion
if (nSize == 1) {
pT->Insert(q(nLeast));
pG[q(nLeast)]->Insert(r(nLeast)));
}
if (pG[q(X)]->Size() == 0)
pT->Insert(q(x));
pG[q(X)]->Insert(r(X));
nSize++;
if (X < nLeast)
nLeast = X;
if (X > nGreatest)
nGreatest = X;
}
nSize = 1
optimization
Original
algorithm
}
18
The revised deletion
Delete(int X) {
nSize--;
if (nSize == 0) {
nLeast = MAXINT;
nGreatest = MININT;
}
else {
pG[q(X)]->Delete(r(X));
if (pG[q(X)]->Size() == 0)
T->Delete(q(X));
…
nSize = 0
optimization
Original
algorithm
19
The revised deletion
if (X == nLeast)
nLeast = pG[pT->Min()]->Min() +
n2 * T->Min();
else if (X == nGreatest)
nGreatest = pG[pT->Max()]->Max() +
n2 * T->Max();
if (nSize == 1) {
pT->Delete(q(nLeast));
pG[q(nLeast)]->Delete(r(nLeast)));
}
Original
algorithm
nSize = 1
optimization
}
20
The revised successor
Successor(int X) {
if (nSize <= 1)
nSize <= 1
return nGreatest;
optimization
else
if (r(X) > pG[q(X)]->Max())
return (pG[pT->Successor(q(X))]->Min() +
n2 * pT->Successor(q(X)))
Original
else
algorithm
return (pG[q(X)]->Successor(r(X)) +
n2 * q(x));
}
21
The limits of the real
universe
The recursive construction will never go many
levels before exceeding the size of the real
universe. For example, if we have a 32-bit
machine and use built-in operations on the
lowest level of size 32, the next level takes N
up to 32*32 = 2^10, the next level already
takes us to N = 2^20, and the next level
makes N greater than the largest existing
computer memories.
22
QA
23
Download