1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
4<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5<head>
6  <meta name="generator" content=
7  "HTML Tidy for Linux/x86 (vers 12 April 2005), see www.w3.org" />
8
9  <title>Priority-Queues</title>
10  <meta http-equiv="Content-Type" content=
11  "text/html; charset=us-ascii" />
12  </head>
13
14<body>
15  <div id="page">
16    <h1>Priority-Queue Design</h1>
17
18    <h2><a name="overview" id="overview">Overview</a></h2>
19
20    <p>The priority-queue container has the following
21    declaration:</p>
22    <pre>
23<b>template</b>&lt;
24    <b>typename</b> Value_Type,
25    <b>typename</b> Cmp_Fn = std::less&lt;Value_Type&gt;,
26    <b>typename</b> Tag = <a href="pairing_heap_tag.html">pairing_heap_tag</a>,
27    <b>typename</b> Allocator = std::allocator&lt;<b>char</b>&gt; &gt;
28<b>class</b> <a href="priority_queue.html">priority_queue</a>;
29</pre>
30
31    <p>The parameters have the following meaning:</p>
32
33    <ol>
34      <li><tt>Value_Type</tt> is the value type.</li>
35
36      <li><tt>Cmp_Fn</tt> is a value comparison functor</li>
37
38      <li><tt>Tag</tt> specifies which underlying data structure
39      to use.</li>
40
41      <li><tt>Allocator</tt> is an allocator
42      type.</li>
43    </ol>
44
45    <p>The <tt>Tag</tt> parameter specifies which underlying
46    data structure to use. Instantiating it by <a href=
47    "pairing_heap_tag.html"><tt>pairing_heap_tag</tt></a>,
48    <a href=
49    "binary_heap_tag.html"><tt>binary_heap_tag</tt></a>,
50    <a href=
51    "binomial_heap_tag.html"><tt>binomial_heap_tag</tt></a>,
52    <a href=
53    "rc_binomial_heap_tag.html"><tt>rc_binomial_heap_tag</tt></a>,
54    or <a href=
55    "thin_heap_tag.html"><tt>thin_heap_tag</tt></a>,
56    specifies, respectively, an underlying pairing heap [<a href=
57    "references.html#fredman86pairing">fredman86pairing</a>],
58    binary heap [<a href="references.html#clrs2001">clrs2001</a>],
59    binomial heap [<a href=
60    "references.html#clrs2001">clrs2001</a>], a binomial heap with
61    a redundant binary counter [<a href=
62    "references.html#maverik_lowerbounds">maverik_lowerbounds</a>],
63    or a thin heap [<a href=
64    "references.html#kt99fat_heaps">kt99fat_heas</a>]. These are
65    explained further in <a href="#pq_imp">Implementations</a>.</p>
66
67    <p>As mentioned in <a href=
68    "tutorial.html#pq">Tutorial::Priority Queues</a>, 
69    <a href=
70    "priority_queue.html"><tt>__gnu_pbds::priority_queue</tt></a>
71    shares most of the same interface with <tt>std::priority_queue</tt>.
72    <i>E.g.</i> if <tt>q</tt> is a priority queue of type
73    <tt>Q</tt>, then <tt>q.top()</tt> will return the "largest"
74    value in the container (according to <tt><b>typename</b>
75    Q::cmp_fn</tt>). <a href=
76    "priority_queue.html"><tt>__gnu_pbds::priority_queue</tt></a>
77    has a larger (and very slightly different) interface than
78    <tt>std::priority_queue</tt>, however, since typically
79    <tt>push</tt> and <tt>pop</tt> are deemed insufficient for
80    manipulating priority-queues. </p>
81
82    <p>Different settings require different priority-queue
83    implementations which are described in <a href=
84    "#pq_imp">Implementations</a>; <a href="#pq_traits">Traits</a>
85    discusses ways to differentiate between the different traits of
86    different implementations.</p>
87
88    <h2><a name="pq_it" id="pq_it">Iterators</a></h2>
89
90    <p>There are many different underlying-data structures for
91    implementing priority queues. Unfortunately, most such
92    structures are oriented towards making <tt>push</tt> and
93    <tt>top</tt> efficient, and consequently don't allow efficient
94    access of other elements: for instance, they cannot support an efficient
95    <tt>find</tt> method. In the use case where it
96    is important to both access and "do something with" an
97    arbitrary value, one would be out of luck. For example, many graph algorithms require
98    modifying a value (typically increasing it in the sense of the
99    priority queue's comparison functor).</p>
100
101    <p>In order to access and manipulate an arbitrary value in a
102    priority queue, one needs to reference the internals of the
103    priority queue from some form of an associative container -
104    this is unavoidable. Of course, in order to maintain the
105    encapsulation of the priority queue, this needs to be done in a
106    way that minimizes exposure to implementation internals.</p>
107
108    <p>In <tt>pb_ds</tt> the priority queue's <tt>insert</tt>
109    method returns an iterator, which if valid can be used for subsequent <tt>modify</tt> and
110    <tt>erase</tt> operations. This both preserves the priority
111    queue's encapsulation, and allows accessing arbitrary values (since the
112    returned iterators from the <tt>push</tt> operation can be
113    stored in some form of associative container).</p>
114
115    <p>Priority queues' iterators present a problem regarding their
116    invalidation guarantees. One assumes that calling
117    <tt><b>operator</b>++</tt> on an iterator will associate it
118    with the "next" value. Priority-queues are
119    self-organizing: each operation changes what the "next" value
120    means. Consequently, it does not make sense that <tt>push</tt>
121    will return an iterator that can be incremented - this can have
122    no possible use. Also, as in the case of hash-based containers,
123    it is awkward to define if a subsequent <tt>push</tt> operation
124    invalidates a prior returned iterator: it invalidates it in the
125    sense that its "next" value is not related to what it
126    previously considered to be its "next" value. However, it might not
127    invalidate it, in the sense that it can be
128    de-referenced and used for <tt>modify</tt> and <tt>erase</tt>
129    operations.</p>
130
131    <p>Similarly to the case of the other unordered associative
132    containers, <tt>pb_ds</tt> uses a distinction between
133    point-type and range type iterators. A priority queue's <tt>iterator</tt> can always be
134    converted to a <tt>point_iterator</tt>, and a
135    <tt>const_iterator</tt> can always be converted to a
136    <tt>const_point_iterator</tt>.</p>
137
138    <p>The following snippet demonstrates manipulating an arbitrary
139    value:</p>
140    <pre>
141<i>// A priority queue of integers.</i>
142<a href=
143"priority_queue.html">priority_queue</a>&lt;<b>int</b>&gt; p;
144
145<i>// Insert some values into the priority queue.</i>
146<a href=
147"priority_queue.html">priority_queue</a>&lt;<b>int</b>&gt;::point_iterator it = p.push(0);
148
149p.push(1);
150p.push(2);
151
152<i>// Now modify a value.</i>
153p.modify(it, 3);
154
155assert(p.top() == 3);
156</pre>
157
158    <p>(<a href="pq_examples.html#xref">Priority Queue
159    Examples::Cross-Referencing</a> shows a more detailed
160    example.)</p>
161
162    <p>It should be noted that an alternative design could embed an
163    associative container in a priority queue. Could, but most probably should not. To begin with, it should be noted that one
164    could always encapsulate a priority queue and an associative
165    container mapping values to priority queue iterators with no
166    performance loss. One cannot, however, "un-encapsulate" a
167    priority queue embedding an associative container, which might
168    lead to performance loss. Assume, that one needs to
169    associate each value with some data unrelated to priority
170    queues. Then using <tt>pb_ds</tt>'s design, one could use an
171    associative container mapping each value to a pair consisting
172    of this data and a priority queue's iterator. Using the
173    embedded method would need to use two associative
174    containers. Similar problems might arise in cases where a value
175    can reside simultaneously in many priority queues.</p>
176
177    <h2><a name="pq_imp" id="pq_imp">Implementations</a></h2>
178
179    <p>There are three main implementations of priority queues: the
180    first employs a binary heap, typically one which uses a
181    sequence; the second uses a tree (or forest of trees), which is
182    typically less structured than an associative container's tree;
183    the third simply uses an associative container. These are
184    shown, respectively, in Figures <a href=
185    "#pq_different_underlying_dss">Underlying Priority-Queue
186    Data-Structures</a> A1 and A2, Figure <a href=
187    "#pq_different_underlying_dss">Underlying Priority-Queue
188    Data-Structures</a> B, and Figures <a href=
189    "#pq_different_underlying_dss">Underlying Priority-Queue
190    Data-Structures</a> C.</p>
191
192    <h6 class="c1"><a name="pq_different_underlying_dss" id=
193    "pq_different_underlying_dss"><img src=
194    "pq_different_underlying_dss.png" alt="no image" /></a></h6>
195
196    <h6 class="c1">Underlying Priority-Queue Data-Structures.</h6>
197
198    <p>Roughly speaking, any value that is both pushed and popped
199    from a priority queue must incur a logarithmic expense (in the
200    amortized sense). Any priority queue implementation that would
201    avoid this, would violate known bounds on comparison-based
202    sorting (see, <i>e.g.</i>, [<a href=
203    "references.html#clrs2001">clrs2001</a>] and <a href=
204    "references.html#brodal96priority">brodal96priority</a>]).</p>
205
206    <p>Most implementations do
207    not differ in the asymptotic amortized complexity of
208    <tt>push</tt> and <tt>pop</tt> operations, but they differ in
209    the constants involved, in the complexity of other operations
210    (<i>e.g.</i>, <tt>modify</tt>), and in the worst-case
211    complexity of single operations. In general, the more
212    "structured" an implementation (<i>i.e.</i>, the more internal
213    invariants it possesses) - the higher its amortized complexity
214    of <tt>push</tt> and <tt>pop</tt> operations.</p>
215
216    <p><tt>pb_ds</tt> implements different algorithms using a
217    single class: <a href="priority_queue.html">priority_queue</a>.
218    Instantiating the <tt>Tag</tt> template parameter, "selects"
219    the implementation:</p>
220
221    <ol>
222      <li>Instantiating <tt>Tag = <a href=
223      "binary_heap_tag.html">binary_heap_tag</a></tt> creates
224      a binary heap of the form in Figures <a href=
225      "#pq_different_underlying_dss">Underlying Priority-Queue
226      Data-Structures</a> A1 or A2. The former is internally
227      selected by <a href="priority_queue.html">priority_queue</a>
228      if <tt>Value_Type</tt> is instantiated by a primitive type
229      (<i>e.g.</i>, an <tt><b>int</b></tt>); the latter is
230      internally selected for all other types (<i>e.g.</i>,
231      <tt>std::string</tt>). This implementations is relatively
232      unstructured, and so has good <tt>push</tt> and <tt>pop</tt>
233      performance; it is the "best-in-kind" for primitive
234      types, <i>e.g.</i>, <tt><b>int</b></tt>s. Conversely, it has
235      high worst-case performance, and can support only linear-time
236      <tt>modify</tt> and <tt>erase</tt> operations; this is
237      explained further in <a href="#pq_traits">Traits</a>.</li>
238
239      <li>Instantiating <tt>Tag = <a href=
240      "pairing_heap_tag.html">pairing_heap_tag</a></tt>
241      creates a pairing heap of the form in Figure <a href=
242      "#pq_different_underlying_dss">Underlying Priority-Queue
243      Data-Structures</a> B. This implementations too is relatively
244      unstructured, and so has good <tt>push</tt> and <tt>pop</tt>
245      performance; it is the "best-in-kind" for non-primitive
246      types, <i>e.g.</i>, <tt>std:string</tt>s. It also has very
247      good worst-case <tt>push</tt> and <tt>join</tt> performance
248      (<i>O(1)</i>), but has high worst-case <tt>pop</tt>
249      complexity.</li>
250
251      <li>Instantiating <tt>Tag = <a href=
252      "binomial_heap_tag.html">binomial_heap_tag</a></tt>
253      creates a binomial heap of the form in Figure <a href=
254      "#pq_different_underlying_dss">Underlying Priority-Queue
255      Data-Structures</a> B. This implementations is more
256      structured than a pairing heap, and so has worse
257      <tt>push</tt> and <tt>pop</tt> performance. Conversely, it
258      has sub-linear worst-case bounds for <tt>pop</tt>,
259      <i>e.g.</i>, and so it might be preferred in cases where
260      responsiveness is important.</li>
261
262      <li>Instantiating <tt>Tag = <a href=
263      "rc_binomial_heap_tag.html">rc_binomial_heap_tag</a></tt>
264      creates a binomial heap of the form in Figure <a href=
265      "#pq_different_underlying_dss">Underlying Priority-Queue
266      Data-Structures</a> B, accompanied by a redundant counter
267      which governs the trees. This implementations is therefore
268      more structured than a binomial heap, and so has worse
269      <tt>push</tt> and <tt>pop</tt> performance. Conversely, it
270      guarantees <i>O(1)</i> <tt>push</tt> complexity, and so it
271      might be preferred in cases where the responsiveness of a
272      binomial heap is insufficient.</li>
273
274      <li>Instantiating <tt>Tag = <a href=
275      "thin_heap_tag.html">thin_heap_tag</a></tt> creates a
276      thin heap of the form in Figure <a href=
277      "#pq_different_underlying_dss">Underlying Priority-Queue
278      Data-Structures</a> B. This implementations too is more
279      structured than a pairing heap, and so has worse
280      <tt>push</tt> and <tt>pop</tt> performance. Conversely, it
281      has better worst-case and identical amortized complexities
282      than a Fibonacci heap, and so might be more appropriate for
283      some graph algorithms.</li>
284    </ol>
285
286    <p><a href="pq_performance_tests.html">Priority-Queue
287    Performance Tests</a> shows some results for the above, and
288    discusses these points further.</p>
289
290    <p>Of course, one can use any order-preserving associative
291    container as a priority queue, as in Figure <a href=
292    "#pq_different_underlying_dss">Underlying Priority-Queue
293    Data-Structures</a> C, possibly by creating an adapter class
294    over the associative container (much as 
295    <tt>std::priority_queue</tt> can adapt <tt>std::vector</tt>).
296    This has the advantage that no cross-referencing is necessary
297    at all; the priority queue itself is an associative container.
298    Most associative containers are too structured to compete with
299    priority queues in terms of <tt>push</tt> and <tt>pop</tt>
300    performance.</p>
301
302    <h2><a name="pq_traits" id="pq_traits">Traits</a></h2>
303
304    <p>It would be nice if all priority queues could
305    share exactly the same behavior regardless of implementation. Sadly, this is not possible. Just one for instance is in join operations: joining
306    two binary heaps might throw an exception (not corrupt
307    any of the heaps on which it operates), but joining two pairing
308    heaps is exception free.</p>
309
310    <p>Tags and traits are very useful for manipulating generic
311    types. <a href=
312    "priority_queue.html"><tt>__gnu_pbds::priority_queue</tt></a>
313    publicly defines <tt>container_category</tt> as one of the tags
314    discussed in <a href="#pq_imp">Implementations</a>. Given any
315    container <tt>Cntnr</tt>, the tag of the underlying
316    data structure can be found via <tt><b>typename</b>
317    Cntnr::container_category</tt>; this is one of the types shown in
318    Figure <a href="#pq_tag_cd">Data-structure tag class
319    hierarchy</a>.</p>
320
321    <h6 class="c1"><a name="pq_tag_cd" id=
322    "pq_tag_cd"><img src="priority_queue_tag_cd.png" alt=
323    "no image" /></a></h6>
324
325    <h6 class="c1">Data-structure tag class hierarchy.</h6>
326
327    <p>Additionally, a traits mechanism can be used to query a
328    container type for its attributes. Given any container
329    <tt>Cntnr</tt>, then <tt><a href=
330    "assoc_container_traits.html">__gnu_pbds::container_traits</a>&lt;Cntnr&gt;</tt>
331    is a traits class identifying the properties of the
332    container.</p>
333
334    <p>To find if a container might throw if two of its objects are
335    joined, one can use <a href=
336    "assoc_container_traits.html"><tt>container_traits</tt></a><tt>&lt;Cntnr&gt;::split_join_can_throw</tt>,
337    for example.</p>
338
339    <p>Different priority-queue implementations have different invalidation guarantees. This is
340    especially important, since as explained in <a href=
341    "#pq_it">Iterators</a>, there is no way to access an arbitrary
342    value of priority queues except for iterators. Similarly to
343    associative containers, one can use
344    <a href=
345    "assoc_container_traits.html"><tt>container_traits</tt></a><tt>&lt;Cntnr&gt;::invalidation_guarantee</tt>
346    to get the invalidation guarantee type of a priority queue.</p>
347
348    <p>It is easy to understand from Figure <a href=
349    "#pq_different_underlying_dss">Underlying Priority-Queue
350    Data-Structures</a>, what <a href=
351    "assoc_container_traits.html"><tt>container_traits</tt></a><tt>&lt;Cntnr&gt;::invalidation_guarantee</tt>
352    will be for different implementations. All implementations of
353    type <a href="#pq_different_underlying_dss">Underlying
354    Priority-Queue Data-Structures</a> B have <a href=
355    "point_invalidation_guarantee.html"><tt>point_invalidation_guarantee</tt></a>:
356    the container can freely internally reorganize the nodes -
357    range-type iterators are invalidated, but point-type iterators
358    are always valid. Implementations of type <a href=
359    "#pq_different_underlying_dss">Underlying Priority-Queue
360    Data-Structures</a> A1 and A2 have <a href=
361    "basic_invalidation_guarantee.html"><tt>basic_invalidation_guarantee</tt></a>:
362    the container can freely internally reallocate the array - both
363    point-type and range-type iterators might be invalidated.</p>
364
365    <p>This has major implications, and constitutes a good reason to avoid
366    using binary heaps. A binary heap can perform <tt>modify</tt>
367    or <tt>erase</tt> efficiently <u>given a valid point-type
368    iterator</u>. However, inn order to supply it with a valid point-type
369    iterator, one needs to iterate (linearly) over all
370    values, then supply the relevant iterator (recall that a
371    range-type iterator can always be converted to a point-type
372    iterator). This means that if the number of <tt>modify</tt> or
373    <tt>erase</tt> operations is non-negligible (say
374    super-logarithmic in the total sequence of operations) - binary
375    heaps will perform badly.</p>
376    <pre>
377
378</pre>
379  </div>
380</body>
381</html>
382