[go: nahoru, domu]

Jump to content

Pairing heap

From Wikipedia, the free encyclopedia

This is an old revision of this page, as edited by Sneftel (talk | contribs) at 11:04, 2 September 2020 (rv - we can argue about the wording ("often" vs "sometimes"?) but the basic claim is an important one and definitely made in the source). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

This template is misplaced. It belongs on the talk page: Talk:Pairing heap.
Pairing heap
Typeheap
Invented1986
Invented byMichael L. Fredman, Robert Sedgewick, Daniel Sleator, and Robert Endre Tarjan
Time complexity in big O notation
Operation Average Worst case
Insert Θ(1)
Find-min Θ(1)  
Delete-min O(log n)  
Decrease-key O(log n)
Merge Θ(1)  
Space complexity

A pairing heap is a type of heap data structure with relatively simple implementation and excellent practical amortized performance, introduced by Michael Fredman, Robert Sedgewick, Daniel Sleator, and Robert Tarjan in 1986.[1] Pairing heaps are heap-ordered multiway tree structures, and can be considered simplified Fibonacci heaps. They are considered a "robust choice" for implementing such algorithms as Prim's MST algorithm,[2] and support the following operations (assuming a min-heap):

  • find-min: simply return the top element of the heap.
  • meld: compare the two root elements, the smaller remains the root of the result, the larger element and its subtree is appended as a child of this root.
  • insert: create a new heap for the inserted element and meld into the original heap.
  • decrease-key (optional): remove the subtree rooted at the key to be decreased, replace the key with a smaller key, then meld the result back into the heap.
  • delete-min: remove the root and do repeated melds of its subtrees until one tree remains. Various merging strategies are employed.

The analysis of pairing heaps' time complexity was initially inspired by that of splay trees.[1] The amortized time per delete-min is O(log n), and the operations find-min, meld, and insert run in O(1) amortized time.[3]

When a decrease-key operation is added as well, determining the precise asymptotic running time of pairing heaps has turned out to be difficult. Initially, the time complexity of this operation was conjectured on empirical grounds to be O(1),[4] but Fredman proved that the amortized time per decrease-key is at least for some sequences of operations.[5] Using a different amortization argument, Pettie then proved that insert, meld, and decrease-key all run in amortized time, which is .[6] Elmasry later introduced elaborations of pairing heaps (lazy, consolidate) for which decrease-key runs in amortized time and other operations have optimal amortized bounds,[7][8] but no tight bound is known for the original data structure.[3][6]

Although this is worse than other priority queue algorithms such as Fibonacci heaps, which perform decrease-key in amortized time, the performance in practice is excellent. Stasko and Vitter,[4] Moret and Shapiro,[9] and Larkin, Sen, and Tarjan[10] conducted experiments on pairing heaps and other heap data structures. They concluded that pairing heaps are often faster in practice than array-based binary heaps and d-ary heaps, and almost always faster in practice than other pointer-based heaps, including data structures like Fibonacci heaps that are theoretically more efficient.

Structure

A pairing heap is either an empty heap, or a pairing tree consisting of a root element and a possibly empty list of pairing trees. The heap ordering property requires that parent of any node is no greater than the node itself. The following description assumes a purely functional heap that does not support the decrease-key operation.

type PairingTree[Elem] = Heap(elem: Elem, subheaps: List[PairingTree[Elem]])
type PairingHeap[Elem] = Empty | PairingTree[Elem]

A pointer-based implementation for RAM machines, supporting decrease-key, can be achieved using three pointers per node, by representing the children of a node by a singly-linked list: a pointer to the node's first child, one to its next sibling, and one to its previous sibling (or, for the leftmost sibling, to its parent). Alternatively, the previous-pointer can be omitted by letting the last child point back to the parent, if a single boolean flag is added to indicate "end of list". This achieves a more compact structure at the expense of a constant overhead factor per operation.[1]

Operations

find-min

The function find-min simply returns the root element of the heap:

function find-min(heap: PairingHeap[Elem]) -> Elem
  if heap is Empty
    error
  else
    return heap.elem

meld

Melding with an empty heap returns the other heap, otherwise a new heap is returned that has the minimum of the two root elements as its root element and just adds the heap with the larger root to the list of subheaps:

function meld(heap1, heap2: PairingHeap[Elem]) -> PairingHeap[Elem]
  if heap1 is Empty
    return heap2
  elsif heap2 is Empty
    return heap1
  elsif heap1.elem < heap2.elem
    return Heap(heap1.elem, heap2 :: heap1.subheaps)
  else
    return Heap(heap2.elem, heap1 :: heap2.subheaps)

insert

The easiest way to insert an element into a heap is to meld the heap with a new heap containing just this element and an empty list of subheaps:

function insert(elem: Elem, heap: PairingHeap[Elem]) -> PairingHeap[Elem]
  return meld(Heap(elem, []), heap)

delete-min

The only non-trivial fundamental operation is the deletion of the minimum element from the heap. This requires performing repeated melds of its children until only one tree remains. The standard strategy first melds the subheaps in pairs (this is the step that gave this data structure its name) from left to right and then melds the resulting list of heaps from right to left:

function delete-min(heap: PairingHeap[Elem]) -> PairingHeap[Elem]
  if heap is Empty
    error
  else
    return merge-pairs(heap.subheaps)

This uses the auxiliary function merge-pairs:

function merge-pairs(list: List[PairingTree[Elem]]) -> PairingHeap[Elem]
  if length(list) == 0
    return Empty
  elsif length(list) == 1
    return list[0]
  else
    return meld(meld(list[0], list[1]), merge-pairs(list[2..]))

That this does indeed implement the described two-pass left-to-right then right-to-left merging strategy can be seen from this reduction:

   merge-pairs([H1, H2, H3, H4, H5, H6, H7])
=> meld(meld(H1, H2), merge-pairs([H3, H4, H5, H6, H7]))
     # meld H1 and H2 to H12, then the rest of the list
=> meld(H12, meld(meld(H3, H4), merge-pairs([H5, H6, H7])))
     # meld H3 and H4 to H34, then the rest of the list
=> meld(H12, meld(H34, meld(meld(H5, H6), merge-pairs([H7]))))
     # meld H5 and H6 to H56, then the rest of the list
=> meld(H12, meld(H34, meld(H56, H7)))
     # switch direction, meld the last two resulting heaps, giving H567
=> meld(H12, meld(H34, H567))
     # meld the last two resulting heaps, giving H34567
=> meld(H12, H34567) 
     # finally, meld the first pair with the result of merging the rest
=> H1234567

Summary of running times

Here are time complexities[11] of various heap data structures. The abbreviation am. indicates that the given complexity is amortized, otherwise it is a worst-case complexity. For the meaning of "O(f)" and "Θ(f)" see Big O notation. Names of operations assume a min-heap.

Operation find-min delete-min decrease-key insert meld make-heap[a]
Binary[11] Θ(1) Θ(log n) Θ(log n) Θ(log n) Θ(n) Θ(n)
Skew[12] Θ(1) O(log n) am. O(log n) am. O(log n) am. O(log n) am. Θ(n) am.
Leftist[13] Θ(1) Θ(log n) Θ(log n) Θ(log n) Θ(log n) Θ(n)
Binomial[11][15] Θ(1) Θ(log n) Θ(log n) Θ(1) am. Θ(log n)[b] Θ(n)
Skew binomial[16] Θ(1) Θ(log n) Θ(log n) Θ(1) Θ(log n)[b] Θ(n)
2–3 heap[18] Θ(1) O(log n) am. Θ(1) Θ(1) am. O(log n)[b] Θ(n)
Bottom-up skew[12] Θ(1) O(log n) am. O(log n) am. Θ(1) am. Θ(1) am. Θ(n) am.
Pairing[3] Θ(1) O(log n) am. o(log n) am.[c] Θ(1) Θ(1) Θ(n)
Rank-pairing[21] Θ(1) O(log n) am. Θ(1) am. Θ(1) Θ(1) Θ(n)
Fibonacci[11][22] Θ(1) O(log n) am. Θ(1) am. Θ(1) Θ(1) Θ(n)
Strict Fibonacci[23][d] Θ(1) Θ(log n) Θ(1) Θ(1) Θ(1) Θ(n)
Brodal[24][d] Θ(1) Θ(log n) Θ(1) Θ(1) Θ(1) Θ(n)[25]
  1. ^ make-heap is the operation of building a heap from a sequence of n unsorted elements. It can be done in Θ(n) time whenever meld runs in O(log n) time (where both complexities can be amortized).[12][13] Another algorithm achieves Θ(n) for binary heaps.[14]
  2. ^ a b c For persistent heaps (not supporting decrease-key), a generic transformation reduces the cost of meld to that of insert, while the new cost of delete-min is the sum of the old costs of delete-min and meld.[17] Here, it makes meld run in Θ(1) time (amortized, if the cost of insert is) while delete-min still runs in O(log n). Applied to skew binomial heaps, it yields Brodal-Okasaki queues, persistent heaps with optimal worst-case complexities.[16]
  3. ^ Lower bound of [19] upper bound of [20]
  4. ^ a b Brodal queues and strict Fibonacci heaps achieve optimal worst-case complexities for heaps. They were first described as imperative data structures. The Brodal-Okasaki queue is a persistent data structure achieving the same optimum, except that decrease-key is not supported.

References

  1. ^ a b c Fredman, Michael L.; Sedgewick, Robert; Sleator, Daniel D.; Tarjan, Robert E. (1986). "The pairing heap: a new form of self-adjusting heap" (PDF). Algorithmica. 1 (1): 111–129. doi:10.1007/BF01840439.
  2. ^ Mehlhorn, Kurt; Sanders, Peter (2008). Algorithms and Data Structures: The Basic Toolbox (PDF). Springer. p. 231.
  3. ^ a b c Iacono, John (2000), "Improved upper bounds for pairing heaps", Proc. 7th Scandinavian Workshop on Algorithm Theory (PDF), Lecture Notes in Computer Science, vol. 1851, Springer-Verlag, pp. 63–77, arXiv:1110.4428, CiteSeerX 10.1.1.748.7812, doi:10.1007/3-540-44985-X_5, ISBN 3-540-67690-2
  4. ^ a b Stasko, John T.; Vitter, Jeffrey S. (1987), "Pairing heaps: experiments and analysis" (PDF), Communications of the ACM, 30 (3): 234–249, CiteSeerX 10.1.1.106.2988, doi:10.1145/214748.214759
  5. ^ Fredman, Michael L. (1999). "On the efficiency of pairing heaps and related data structures" (PDF). Journal of the ACM. 46 (4): 473–501. doi:10.1145/320211.320214. Archived from the original (PDF) on 2011-07-21. Retrieved 2011-05-03.
  6. ^ a b Pettie, Seth (2005), "Towards a final analysis of pairing heaps" (PDF), Proc. 46th Annual IEEE Symposium on Foundations of Computer Science (PDF), pp. 174–183, doi:10.1109/SFCS.2005.75, ISBN 0-7695-2468-0
  7. ^ Elmasry, Amr (2009), "Pairing heaps with O(log log n) decrease cost" (PDF), Proc. 20th Annual ACM-SIAM Symposium on Discrete Algorithms, pp. 471–476, CiteSeerX 10.1.1.502.6706, doi:10.1137/1.9781611973068.52
  8. ^ Elmasry, Amr (November 2017). "Toward Optimal Self-Adjusting Heaps" (PDF). ACM Transactions on Algorithms. 13 (4): 1–14. doi:10.1145/3147138.
  9. ^ Moret, Bernard M. E.; Shapiro, Henry D. (1991), "An empirical analysis of algorithms for constructing a minimum spanning tree", Proc. 2nd Workshop on Algorithms and Data Structures, Lecture Notes in Computer Science, vol. 519, Springer-Verlag, pp. 400–411, CiteSeerX 10.1.1.53.5960, doi:10.1007/BFb0028279, ISBN 3-540-54343-0
  10. ^ Larkin, Daniel H.; Sen, Siddhartha; Tarjan, Robert E. (2014), "A back-to-basics empirical study of priority queues", Proceedings of the 16th Workshop on Algorithm Engineering and Experiments, pp. 61–72, arXiv:1403.0252, doi:10.1137/1.9781611973198.7
  11. ^ a b c d Cormen, Thomas H.; Leiserson, Charles E.; Rivest, Ronald L. (1990). Introduction to Algorithms (1st ed.). MIT Press and McGraw-Hill. ISBN 0-262-03141-8.
  12. ^ a b c Sleator, Daniel Dominic; Tarjan, Robert Endre (February 1986). "Self-Adjusting Heaps". SIAM Journal on Computing. 15 (1): 52–69. CiteSeerX 10.1.1.93.6678. doi:10.1137/0215004. ISSN 0097-5397.
  13. ^ a b Tarjan, Robert (1983). "3.3. Leftist heaps". Data Structures and Network Algorithms. pp. 38–42. doi:10.1137/1.9781611970265. ISBN 978-0-89871-187-5.
  14. ^ Hayward, Ryan; McDiarmid, Colin (1991). "Average Case Analysis of Heap Building by Repeated Insertion" (PDF). J. Algorithms. 12: 126–153. CiteSeerX 10.1.1.353.7888. doi:10.1016/0196-6774(91)90027-v. Archived from the original (PDF) on 2016-02-05. Retrieved 2016-01-28.
  15. ^ "Binomial Heap | Brilliant Math & Science Wiki". brilliant.org. Retrieved 2019-09-30.
  16. ^ a b Brodal, Gerth Stølting; Okasaki, Chris (November 1996), "Optimal purely functional priority queues", Journal of Functional Programming, 6 (6): 839–857, doi:10.1017/s095679680000201x
  17. ^ Okasaki, Chris (1998). "10.2. Structural Abstraction". Purely Functional Data Structures (1st ed.). pp. 158–162. ISBN 9780521631242.
  18. ^ Takaoka, Tadao (1999), Theory of 2–3 Heaps (PDF), p. 12
  19. ^ Fredman, Michael Lawrence (July 1999). "On the Efficiency of Pairing Heaps and Related Data Structures" (PDF). Journal of the Association for Computing Machinery. 46 (4): 473–501. doi:10.1145/320211.320214.
  20. ^ Pettie, Seth (2005). Towards a Final Analysis of Pairing Heaps (PDF). FOCS '05 Proceedings of the 46th Annual IEEE Symposium on Foundations of Computer Science. pp. 174–183. CiteSeerX 10.1.1.549.471. doi:10.1109/SFCS.2005.75. ISBN 0-7695-2468-0.
  21. ^ Haeupler, Bernhard; Sen, Siddhartha; Tarjan, Robert E. (November 2011). "Rank-pairing heaps" (PDF). SIAM J. Computing. 40 (6): 1463–1485. doi:10.1137/100785351.
  22. ^ Fredman, Michael Lawrence; Tarjan, Robert E. (July 1987). "Fibonacci heaps and their uses in improved network optimization algorithms" (PDF). Journal of the Association for Computing Machinery. 34 (3): 596–615. CiteSeerX 10.1.1.309.8927. doi:10.1145/28869.28874.
  23. ^ Brodal, Gerth Stølting; Lagogiannis, George; Tarjan, Robert E. (2012). Strict Fibonacci heaps (PDF). Proceedings of the 44th symposium on Theory of Computing - STOC '12. pp. 1177–1184. CiteSeerX 10.1.1.233.1740. doi:10.1145/2213977.2214082. ISBN 978-1-4503-1245-5.
  24. ^ Brodal, Gerth S. (1996), "Worst-Case Efficient Priority Queues" (PDF), Proc. 7th Annual ACM-SIAM Symposium on Discrete Algorithms, pp. 52–58
  25. ^ Goodrich, Michael T.; Tamassia, Roberto (2004). "7.3.6. Bottom-Up Heap Construction". Data Structures and Algorithms in Java (3rd ed.). pp. 338–341. ISBN 0-471-46983-1.