DeepAI
Log In Sign Up

Fast Fibonacci heaps with worst case extensions

We are concentrating on reducing overhead of heaps based on comparisons with optimal worstcase behaviour. The paper is inspired by Strict Fibonacci Heaps [1], where G. S. Brodal, G. Lagogiannis, and R. E. Tarjan implemented the heap with DecreaseKey and Meld interface in assymptotically optimal worst case times (based on key comparisons). In the paper [2], the ideas were elaborated and it was shown that the same asymptotical times could be achieved with a strategy loosing much less information from previous comparisons. There is big overhead with maintainance of violation lists in these heaps. We propose simple alternative reducing this overhead. It allows us to implement fast amortized Fibonacci heaps, where user could call some methods in variants guaranting worst case time. If he does so, the heaps are not guaranted to be Fibonacci until an amortized version of a method is called. Of course we could call worst case versions all the time, but as there is an overhead with the guarantee, calling amortized versions is prefered choice if we are not concentrated on complexity of the separate operation. We have shown, we could implement full DecreaseKey-Meld interface, but Meld interface is not natural for these heaps, so if Meld is not needed, much simpler implementation suffices. As I don't know application requiring Meld, we would concentrate on noMeld variant, but we will show the changes could be applied on Meld including variant as well. The papers [1], [2] shown the heaps could be implemented on pointer machine model. For fast practical implementations we would rather use arrays. Our goal is to reduce number of pointer manipulations. Maintainance of ranks by pointers to rank lists would be unnecessary overhead.

READ FULL TEXT VIEW PDF

page 1

page 2

page 3

page 4

11/11/2019

Information carefull worstcase DecreaseKey heaps with simple nonMeld variant

We analyze priority queues including DecreaseKey method in its interface...
10/04/2020

Fast DecreaseKey Heaps with worst case variants

In the paper "Fast Fibonacci heaps with worst case extensions" we have d...
11/02/2018

Worst-Case Efficient Sorting with QuickMergesort

The two most prominent solutions for the sorting problem are Quicksort a...
07/27/2021

Efficient Parallel Graph Trimming by Arc-Consistency

Given a large data graph, trimming techniques can reduce the search spac...
06/09/2021

Pattern-defeating Quicksort

A new solution for the Dutch national flag problem is proposed, requirin...
07/24/2020

Corpse Reviver: Sound and Efficient Gradual Typing via Contract Verification

Gradually-typed programming languages permit the incremental addition of...
05/10/2018

Nearly-Optimal Mergesorts: Fast, Practical Sorting Methods That Optimally Adapt to Existing Runs

We present two stable mergesort variants, "peeksort" and "powersort", th...

1 Introduction

We will call heaps from the paper [StrictHeaps] BLT heaps as their connection to Fibonacci is only negligable. We will call the heaps in paper [sewc] as BLMT heaps, with Meld and noMeld variants. The BLT (resp. BLMT) heaps strategy is not to be too pedantic to the heap shape and allow some types of violations. Violation sizes of each type are maintained bounded by maximal rank plus 1. What gives quadratic inequality bound for leading to . To maintain degrees bounded by in Meld variants, list of heap nodes is required and first two nodes are moved to the end of the list after each heap size decrement by 1. The degree reduction is performed on moved nodes. This ensures the ( position in the list) remains constant for all except moved nodes so degree bounds by funcion could be maintained. For noMeld variant no degree reductions are required and no list of heap nodes is needed.

The violations are maintained in violation structures in BLT/BLMT heaps. In conlcluding remarks of [sewc] the big overhead with their maintainance is mentioned and caching is recomended. Our goal is to reduce violation structures at all, and use same rank identifying places with caching instead. Amortized versions would simply empty the caches at the end of each operation. Worst case versions would need to plan the reductions and count the reductions made not to exceed the declared time. We have to propose violation/cache reduction strategy to ensure the violation sizes remain bounded by at the same time.

With empty cache for loss violations we have guarentee no node have loss greater 1, what is condition maintained at Fibonacci heaps, therefore at these times Fibonacci sequence bounds the sizes of subtrees of nodes of given rank. Actually for big the total loss bound by is more restrictive than local loss bound at each node. So only for small ranks (and empty cache) the Fibonacci bound applies. The trees with bigger ranks are bounded more by total loss. This is on the edge to call them Fibonacci. Calling them (local/)global loss bounded would be more appropriate.

2 Overhead of violation structures

Violations in BLT/BLMT heaps are maintained in double linked lists pointed inside from ranks. Adding a violation first of the rank means making pointer from rank to the node and inserting listnode to the corresponding list end. This is why end list pointer changes and 2 pointers in neighbours are updated (and one remains null) so at least 4 pointer updates are required. Adding 2nd violation of the same rank removes node pointed by rank from the list, and inserts pair of nodes to the other end of the list. This changes 2 neighbour pointers around removed node from the list, sets 2 pointers among the pair of nodes of the same rank and changes end list pointer and 2 pointers connecting the inserted pair with the list. This makes 7 pointer changes. When node with loss 1 gets 2nd loss, it was pointed by rank pointer and there is exactly one other node of the same rank in the violation list, the update is even bigger. Rank pointer should be changed, the other node of the rank should be removed from the list and reinserted to the end of the list. The loss 2 node representant should be removed from the list as well and reinserted to the other end of the list. This affects 2 pointers to reconnect the list near removal, both list end pointers change and both moved nodes change both neighbours (null at end of the list should be changed to inserted node, inserted node should change one pointer to neighbour and the other to null). This sums to 11 pointer changes. Violation reduction steps remove upto two nodes from corresponding list end and either update rank pointer or if there is just one node remaining of affected rank, the node is removed and reinserted to the other list end. This affects at most 6 pointers (not counting overhead by garbage collector of reduced nodes).

We propose using same rank identifying places and cache of not yet inserted violations. On pointer machine model the list of ranks could be used as same rank identifying places (with one pointer reserved in the list node for each type of violation). We would recomend array for each type of violation indexed by numeric ranks when pointer machine model is not required.

Cache could be any set structure supporting insert of a pointer value and pop (removing an arbitrary pointer value from the set and returning it). Single link list could be used on pointer machine requiring 2 pointer changes per update. Array (with guaranted sufficient size) requiring 1 pointer change and one index value change per insert and no pointer change and one index value change per pop is recomended when pointer machine model is not needed.

Each violation would be inserted to the cache and cache would be processed during cache reductions. As each node could be part of at most one violation type, we would maintain the type identification in the node (could be empty, loss could be identified here as well). When node changes rank, it allows us to localise the violation set to update the node rank here (to remove, change, and reinsert). The removal from corresponding type of violation would check corresponding pointer in same rank identifying place. If it points to the node, we just change it to null. Otherwise we just remember it is in the cache. This would leave the violation update in cache. If the node should be reinserted to the same violation type we insert it to cache (unless we know it is there already). If the node should be reinserted as other violation type, we insert it to the corresponding cache, but update the type of violation to which it should belong. If the node is no more violation, we should empty the type identification maintained in it. This means node could be even several times in several caches, but it would represent at most one violation of its current violation type.

When node from cache is processed during cache reduction, we at first check it belongs to the type of violation. If not, we just discard the cache info. We will discard the cache info even when corresponding rank identifying place points to the node. When the node is loss violation (allowed on loss violation cache), we do corresponding single node loss reduction immediately. Otherwise we check the same rank identifying place for the node rank. If it contains pointer to the processed node, we just discard the cache info. If it contains null, the pointer to the node is inserted there. Otherwise we have pointers to two nodes of the same rank and corresponding violation reduction is performed. This puts null to the same rank identifying place and could insert new violations to corresponding caches.

We actually use same rank identifying places the way it is used in FindMin of amortised versions of Binomial/Fibonacci/Padovan heaps except we leave the pointers in the places even after FindMin is finished. This reduces the overhead with same rank identifying places of Binomial/Fibonacci/Padovan heaps.

The arrays would be preferable choice regarding to hardware caches. Using arrays in noMeld variant is natural, especially when we could predict the maximal heap size, otherwise we could use worstcase variant of array doubling. The array doubling overhead would be negligable as the arrays are of logarithmic sizes. Worstcase variant of array doubling would work even in Meld variant, it would need to copy two slots per array and operation in scenario long sequence of melds of equally sized heaps occurs. Most other times the array would be filled less than from half so no copying is needed.

3 Structure balancing overview

Except the introduction of caches and change on their maintanance strategy the heaps would work as in [sewc]. In the Meld variant there would be deffered and solid nodes, where deffering could be implicit. Solid children would be either rank or nonrank. The number of rank children correspond to rank of the node which is bounded by some function . Solid nonrank child is a rank tree root. We will maintain all rank tree roots as violations to ensure, their number does not exceed . Unfortunately if we would maintain all rank tree roots together, violation reductions would allow series where increase of degree would force degree reduction resulting in new rank tree root violation so there will be no visible progress in reducing rank tree roots count. Therefore we crerate two violation types for rank tree roots, one where the roots with guaranted degree reserves are added and the others (this prevents eager conversion of most defered children to solid). Each degree reduction ensures the guarantee and linking two guaranted rank roots does not require the degree reduction. Therefore the number of rank roots is bounded by , one of them is the main root so at most rank roots could be children.

We would maintain all nodes with loss as violation of loss type. The number of solid children is therefore bounded by where is maximal posible rank for heap with nodes and total loss at most

. Estimating the bigger root of the corresponding quadratic equation gives us

.

In the case there could be deffered children (Meld variant) we should maintain number of children bounded by explicitly. It is sufficient to regularly do node degree reductions. This reduction either reduces the degree of a node by 2 or ensures the node has no more than 2 deffered children. Each Meld ensures the bounds hold for newly implicitly deffered nodes and the bounds do not decrease for other nodes. Whenever heap size is decremented (due to DeleteMin) two heap nodes are degree reduced and their bounds are changed. List of heap nodes, removing first two nodes from it and inserting them as last two (after two node degree reductions) would do needed, when bounds are defined by function of , where is position of the node in the list, and is small natural number depending on node being solid without loss or not. Actually allows one more children (4+1) for solid nodes with zero loss than for others (4). The degree reductions would maintain the bounds implicitly without knowing their actual values.

We would present the Meld variant first and the simple noMeld variant at the end.

4 Violation reductions

width 14cm sewc_red.pdf 0 -0.56 0.56 0 Figure 1: Reductions to maintain the heap shape with complications for Meld support
Reduction
node degree
discard
type no match
type matched
 - no 3 deffered chidren
 - 3 deffered children
discard
type no match
type matched
discard
subtype
 - parent G in
 - parent G in
 - parent A in
 - parent A in
 - parent L in
 - parent L* in
 - parent N no 3 deffered children
 - parent N 3 deffered children
subtype no match
subtype matched
 - parent of G in
 - parent of G in
 - parent of A in
 - parent of A in
 - parent of L in
 - parent of L* in
 - parent of N

Here denotes number of pointer changes not reflected in heap trees during reduction when arrays are used for caches. We can see each cache reduction decrements by at least 1.

Table 1: Effect of different transformations

Deffered nodes would be made by the Meld method. Similarly as in BLT heaps, the nodes of smaller heap would become deffered implicitly. Implicitly deffered nodes cannot have solid children. Deffered nodes would be accessed during degree reductions of their parents, and during DeleteMins, when the heap root was deffered node parent or by degree reduction of the deffered node reflecting decrease of heap size when moved from the start of heap node list to its end. When the implicitly deffered node is firstly accessed, the pointer responsible for implicit deffering is removed and the node is converted to explicitly deffered. Its heap pointer is redirected to current heap. All its children are deffered (either implicitly or explicitly) in this time, so they are rightmost. No solid rank child is allowed for explicitly deffered nodes, but nonrank solid children are allowed. Deffered nodes violation type is (no violation) by default.

Degree reduction step on a node would be made similarly as root degree reduction on BLT heaps. If node is implicitly deffered, it is converted to explicitly deffered. If the rightmost 3 children are deffered, we convert them to explicitly deffered if not converted yet and we remove them from children list of . We made 3 comparisons to find order of their keys, let node have the smallest, the middle, and the highest key. We continue by making and solid. We create rank edge making root of rank 1 having solid rank child of rank 0. We make a deffered child of , whose rank would stay 0. Finaly is linked as a nonrank (leftmost) child of . Degree constraints are OK for and as they become solid with loss 0. New rank root without guaranted degree reserve was created. Degree of was reduced by 2.

Rank roots without guaranted reserve would be maintained as violations of type . Violations of type would be inserted to cache and from the cache to the same rank identifying places . Similarly rank roots with guaranted reserve would be maintained as violations of type using cache and same rank identifying places .

During reduction if processed cache node is already not of type , the cache item is discarded. The cache item is discarded as well if for ’s rank points to . Other case is for ’s rank contains null, than pointer is stored there, and reduction step ends. Last, and the most important case is when for ’s rank pointed to other violation of the same rank and actual violation type , reduction step could be applied after putting null to of ’s rank. Violation reduction step of type links nodes , of the same rank. (Their keys are compared, let node be the one with smaller key while the other. We cut from its parent (if there exists nonrank edge) and put it as a rank child of . This increases rank of as well as it’s degree. Degree reduction is performed on what makes active root with guaranted reserve. So violation type is changed to , the active root possibly created by the degree reduction would be added to . Node violation type is changed to , and is added to .)

During reduction the simillar trivial cases appear (just use , resp. instead of , resp. ). Last, and the most important case is violation reduction step of type linking nodes , of the same rank after putting null to of ’s rank. (Their keys are compared, let node be the one with smaller key while the other. We cut from its parent (if there exists nonrank edge) and put it as a rank child of . This increases rank of as well as it’s degree. Degree reduction is not performed on as there was degree reserve. So violation type is changed to , violation type to and is added to .)

Whenever rank child’s rank is decremented, its loss is incremented. All nodes with nonzero loss would be maintained as violations of type , this type has subtype for nodes with loss exactly 1 and subtype for nodes with loss at least 2. Violations of type would be inserted to cache , from which violations of subtype will be inserted to same rank identifying places . Symbol has weighted meaning. Weight of nodes of subtype corresponds to the loss of the node, while others weight is 1 (including nodes of other type than ).

Similarly as for reduction, when during reduction node is already not of type or of ’s rank points to , the cache item is discarded. Different is the second case when ’s subtype is . It invokes one node loss reduction, which takes node with loss at least 2, it makes it nonrank child of it’s parent . This creates new rank root (with loss 0 and guaranted degree reserve), so is put to and violation type of is changed to . The rank of is decremented. Unless violation type of is , should be removed from the rank identifying place identified by its type (If there was null in the place, we know resists in the cache). If is a rank child it should be inserted to and type changed to (if it does not resist there), its loss is increased and subtype changed accordingly. Total loss was reduced by at least 1. Degree of could have been on it’s limit and the limit was decremented if the loss changed from 0 to 1, therefore degree reduction should be called on if it changed loss from 0 to 1 (what could insert new violation of type to ). If was a rank root, its violation type does not change as both limit and degree did not changed so should be just inserted to the cache of the type unless it already resists there. Third case of reduction is for subtype when the rank identifying place of ’s rank contains null. As for reduction the pointer to is stored in and the reduction step ends. Last case is when for ’s rank (for node of subtype ) pointed to other violation of the same rank and actual violation type reduction step could be applied after putting null to of ’s rank. Violation reduction step of type for nodes , of equal rank and loss 1 links the two nodes. (Their keys are compared, let and be the nodes with higher and smaller keys respectively. Remove from it’s parent and link it under by a rank edge. This reduces loss of to 0 and sets loss of to 0, so both and violation types are changed to . Original parent of decrements rank by 1. Unless violation type of is , should be removed from the rank identifying place identified by its type (If there was null in the place, we know resists in the cache). If is a rank child its type should be changed to and inserted to (if it does not resist there), and its loss is increased and subtype changed accordingly. Total loss was reduced by at least 1. Degree constraint for is OK as well as for . If was rank root, it got degree reserve so its type should be changed to and should be inserted to (if it does not resist there).)

In the Figure 1 you can see the reductions and in Table 1 you can see the effect of reductions.

For amortized versions, we do cache reductions unless all caches are empty. The process must terminate as is decremented by each cache reduction. could be used as potential to pay for the cache reductions. Strategy to maintain violations in bounds would for worst case variants calculate changes of , , from the start of the method. In each coordinate the positive change at the method end is allowed only in the case the corresponding cache is empty. So while a coordinate has positive change and nonempty cache, the corresponding cache reduction step is invoked. Again as is decremented by each cache reduction, we could simply bound the number of required reductions.

Let , , be the values at the start of reducing process, let , , and . Violation reductions could not finish earlier providing we start with at least same coordinates of so if we bound the number of violation steps providing we start at , , , this would bound the real value.

Let , , be the values at the end of reducing process starting from , , . 3 deffered children case reduces coordinates at least as no 3 deffered children case, so we can exclude it from analysis, as well as cases when cache item is just discarded. Let us exclude reducing case which decrement because it reduces coordinates at least as the next case in the table. Now all remaining cases reduce only one coordinate, remaining coordinates could be only increased. Than as each reduction of decreases by at most 7. Similarly as each nonexcluded reduction of decreases by at most 5. If we consider the last |LC| decreasing step as decreasing by 1, change of would be still at most and would change by at most . As decreases by each considered reduction by at least , there could be at most reduction steps in total.

We know , , and . This defines equilibrium values of for the case , for the case , and for the case . We will always use amortized versions of DeleteMin which has the worstcase time . This guarantees after each heap size decrement coordinates would be at at most equilibrium values. When a worstcase method is called, we got either smaller coordinate or empty cache so a coordinate never increases above the equilibrium value. But the bounds by , bounds by and bounds by so number of nodes of violation type is bounded by , number of nodes of violation type is bounded by , and total loss is bounded by .

Degree reduction gives us equilibrium bounds for node degrees. We already know the number of solid children does not exceed . If it has at least children, at least 3 must be deffered and degree reduction can be performed. For our analysis it would be fine to define degree bounds for solid nodes with loss 0 and for other nodes (with being position in the global list of nodes). With estimate we got resp. so we have to plan degree reduction by 4 when moving from start of the heap node list to its end to compensate for decrement, what corresponds to planning two degree reduction steps for a checked node.

As in BLT heaps, linking of rank roots which are nonrank children introduces situation which cannot happen when comparing only tree roots. In the case keys could be equal, random choice of result would allow chosing to be predecessor of resulting in broken tree and a cycle. To prevent this we should expect keys are all different. If this is not guaranted from outside, solution is to generate (different) id’s for key nodes and broke ties by id’s comparisons.

5 Heap structure

Heap information contains size info inicialized to 0, reference count initialised to 0, pointers to list of heap tree roots, and to the list of all heap nodes. It contains same rank identifying places , , and the caches , and . All the lists are maintained double linked, left pointers are maintaned cyclic (left of leftmost points to rightmost). This allows access of both ends in constant time as well as adding or removing of a given node. List of heap tree roots uses sibling pointers maintained in the heap nodes. All heap nodes could have pointers internally in heap nodes as well.

In the pointer machine case we would maintain double linked list of ranks and rank would be represented by poiter to it. In the array version this is not required and we use arrays with worstcase doubling instead. We would implement caches as stacks (last in first out).

When the size info is and the reference count is 0, the heap information is discarded.

Whether the node is rank child, nonrank child or explicitly deffered is maintained in the node state, but this is overriden by being a heap tree root or being implicitly deffered.

Each node which points to the heap information with size info is implicitly deffered. It could be made explicitly deffered by pointing to current heap and setting corresponding state. The reference counter for original heap should be decremented and reference counter on current heap incremented.

6 Implementation of methods

We will describe the methods using private blocks. Their use could be slightly optimized (for example replacing pointer twice during a method without reading it between changes could be avoided). Decomposition into blocks makes the description easier.

Method
heap size decrement
set violation type
 | from
 | from
 | from
 | from
set violation type
 | from
 | from
 | from
 | from
set violation type
 | from
 | from
 | from
 | from
set violation type
 | from
 | from
 | from
 | from
rank decrement
 | rank root
 | rank root
 |
 |
 |
add a solid child
 |
 |
 | or
child removal
link
 + removal from
 + add as child to
 + type to
link of rank roots

Here again denotes number of pointer changes not reflected in heap trees when arrays are used for caches. (Including the heap node list pointer cahnges).

Table 2: Effect of private blocks to violations

Before a public worst case method is called, the coordinates does not exceed the equilibrium values. During the method the coordinates changes are maintained. Worstcase version of FindMin performs cache reductions as mentioned in the previous two sections. Each other public method calls FindMin and does not introduce new violations after the return.

Whenever we decrement size of the heap, we decrement the reference count as well, we two times remove first node of the list of heap nodes (if it exists), we make two degree reductions on and put to the end of the list. This makes the degree constraints to hold for all nodes of the heap (assuming they have held prior to the decrement).

Whenever we set violation type of a node , we remove from the same rank identifying place of the original type (unless the type is ). And we insert it to cache corresponding to the new type (unless the type is or we know the node is already there).

Whenever we decrement rank of a node , violations should be made up to date. We should know if decrement is done by ) rank child removal or ) rank child conversion to nonrank child. In the case is rank root, violation type should be set to in case and to its original value in case 111by the already described method. In the case is not rank root, it’s loss is increased. If violation type is the loss becomes 1, we set violation type to and subtype to . If the loss was 1 (violation type and subtyle ), we set violation type to and subtype to . Only in the case loss of was at least 2 (violation type and subtype ), we know has proper type and subtype and is in so no update is needed.

Whenever we add a solid child to a rank root , must have or violation type. Violation type should be set to the other. When the type changed from to we should call the degree reduction on (what could create a new violation of type ) to finish the rank increment. There is no sideeffect when we add a child to a rank child.

Removal of a child of parent means following: In all cases the parent pointer of would be set to null and would be removed from the children list of and added to the list of heap tree roots. If was a rank child, rank of is decremented.

To link two solid nodes means comparing their keys, let node be the one with smaller key while the other. If had no parent, it is simply removed from its sibling list. Otherwise removal of a child of its parent is invoked. Node is added as a solid (therefore as leftmost) child of  marking rank child if the nodes had equal rank and nonrank otherwise. If a rank child was added, rank of should be incremented and type of violation of set to .

Method
Insert
 + FindMin phase 0
 + FindMin phase 2
FindMin
DeleteMin
 + heap size decrement
 + removal from heap nodes
 + type to

 + FindMin phase 0
 +
 + FindMin phase 2
DecreaseKey
 + child removal
 + FindMin phase 0
 + FindMin phase 2
Meld (, )
 + FindMin phase 0
 + FindMin phase 2

Here again denotes number of pointer changes not reflected in heap trees when arrays are used for caches. (Including the heap node list pointer cahnges).

DeleteMin requires at most cache size reductions in amortized sense. It would generate at most pointer change overhead. If be potential before and after DeleteMin, we should include the difference into account as well. But and . So we have worst case bound cache reductions. It would generate at most pointer change overhead in worst case.

Table 3: Effect of public methods to violations

MakeHeap inicializes the heap structure.

Insert() creates new solid node with violation type , key , rank 0, no parent and no child, pointing to the heap. It increments the heap size and reference count in the heap information without side effects. It adds as a new root to the list of heap tree roots and invokes FindMin. Insert returns for further references.

FindMin traverses nodes of heap tree roots list and makes their parent pointers explicitly to null. It converts implicitly deffered roots to explicitly deffered and (even new) explicitly deffered to solid, the newly solid roots violation type is set to . Violation type of a root which was already solid is checked to be either or . If not, it is set to . This finishes phase 0.

In the worst case variant, the changes to coordinates were calculated and cache size reductions are performed whenever corresponding is positive and cache is nonempty, until all coordinates with positive have empty caches. In the amortized variant is not calculated at all and cache size reductions are performed until caches are empty. This finishes phase 1.

Than FindMin traverses the heap tree roots leftwise linking two neighbouring roots interlaced with steps to left in the circular list (to link the roots as even as possible). We finish when only one tree remains. It’s root points to minimum and it will be returned. are updated during phase 2 (of worst case variant) as well and reduction of cache sizes is repeated at the phase 3 what is last phase of FindMin.

DeleteMin implements only amortized variant, which has guaranted worst case time , so no maintainance of coordinates is needed. It decrements size in the heap information. Let be the only tree root. It updates pointer to the list of roots to point to the leftmost child of . It removes from list of heap nodes and sets violoation type of to . At the end it calls FindMin and discards .

DecreaseKey(, ) removes from its parent  if such parent exists. Than in all cases it updates key at node to . It invokes FindMin at the end.

Meld(, ) identifies smaller heap and larger by comparing size info in the heap informations (call with a heap of size info is invalid). It appends list of nodes to start of the list of nodes (and sets corresponding pointer at to null). As position nodes of in the new list remain same, but the heap size at least doubles, increases by at least so we got reserve 1 in degree bounds so we could make solid node with loss 0 of deffered node of without violating degree constraint bounds (for other nodes of it is even more obvious). It stores sum of the sizes in the heap informations and changes size in to -1, that makes all nodes implicitly deffered. It appends roots of trees list of to the front of roots of trees list of (and sets them to null in ). The same rank identifying places and caches of are discarded. So contains only negative size info and reference counts to allow discard after no implicit deffering is caused by . Finally it invokes FindMin and returns as a current heap.

We can see the effect of public methods on coordinates and pointer overhead in the table 3. Together with reduction of caches we got at most cache size reductions and in additional pointer overhed for amorized version (amortized) of other methods than DeleteMin. This with cache reductions makes pointer overhead at most per such method. With worst case version the upper bound is cache size reductions and in additional pointer overhed so overhead at most pointer changes (and constant time) is guaranted.

There is alternative not to calculate coordinates during worst case methods and use their upper bounds instead and plan cache reductions according the upper bounds. If it’s sufficient to guarantee worstcase bounds, simpler strategy is to keep caches , empty and do two cache reductions after each .

7 Simplification when Meld is not needed

There will be no need for pointers to heap, no need to maintain heap size and the heap reference count. As deffered nodes are created only by Meld method, there will be no deffered nodes in the heap at all. Therefore all nonrank nodes will be rank roots. Their number is limited by their maintenance in violation lists by . This makes degrees bounded by and the degree reduction is impossible and it is not needed at all. All nodes have implicitly degree reserve, so there is no need to maintain rank roots with two different violation types and one violation type say suffices. The global node list to organize degree reductions is not needed as well. So the only support needed are the two volation types and with same rank identifying places and caches. If there are no deffered nodes, we would prefere inserts of nonrank nodes rather to right end of children lists for aesthetic reasons.

Reduction
type
type no match
type matched
type
subtype
 - parent A in
 - parent A in
 - parent L in
 - parent L* in
 - parent N
subtype no match
subtype matched
 - parent of A in
 - parent of A in
 - parent of L in
 - parent of L* in
 - parent of N

Here denotes number of pointer changes not reflected in heap trees during reduction when arrays are used for caches. We can see each cache reduction decrements by at least 1.

Table 4: Effect of different transformations

The violation reduction steps would simplify as shown in Table 4. simplifies to with coordinates and . could pay for violation reductions in amortized case, the analysis for worstcase case would show that there could be at most reduction steps in total. Maximal degree would be .

Method
set violation type
 | from
 | from
 | from
set violation type
 | from
 | from
 | from
set violation type
 | from
 | from
 | from
rank decrement
 |
 |
 |
 |
add a solid child
 |
 | or
child removal
link
 + removal from
 + add as child to
 + type to
link of rank roots

Here again denotes number of pointer changes not reflected in heap trees when arrays are used for caches. (Including the heap node list pointer cahnges).

Table 5: Effect of private blocks to violations
Method
Insert
 + FindMin phase 0
 + FindMin phase 2
FindMin
DeleteMin
 + type to
 + FindMin phase 0
 + FindMin phase 2
DecreaseKey
 + child removal
 + FindMin phase 0
 + FindMin phase 2

Here again denotes number of pointer changes not reflected in heap trees when arrays are used for caches. (Including the heap node list pointer cahnges).

DeleteMin requires at most cache size reductions in amortized sense. It would generate at most pointer overhead. If be potential before and after DeleteMin, we should include the difference into account as well. But and . So we have worst case bound cache reductions. It would generate at most pointer change overhead in worst case.

Table 6: Effect of public methods to violations

We can see the effect of public methods on coordinates and pointer overhead in the table 6. Together with reduction of caches we got at most cache size reductions and in additional pointer overhed for amorized version (amortized) of other methods than DeleteMin. This with cache reductions makes pointer overhead at most per such method. With worst case version the upper bound is cache size reductions and in additional pointer overhed so overhead at most pointer changes (and constant time) is guaranted.

8 Concluding remarks

We have not discussed problems with ids to make heap keys unique. Usually incrementing global count (much bigger range than available memory) would be sufficient. Garbage collection could help not to increment the count too often when the heap size is maintained almost constant. With usage where heap size oscilates among small and big sizes the garbage should be discarded to keep structure size proportional to represented set. In such a scenario when pool of counts is going to be exhausted, nodes of all the heaps could be traversed and ordered temporary set of used id’s constructed. The ids could be replaced by their order in the set. This overhead could be distributed among long enough sequence of operations.

9 Summary

We have shown a variant of worst case heaps not losing information by repeated linking of heap nodes under the heap roots could be implemented and the overhead af the heaps could be kept in reasonable bounds. Especially for heaps not requiring Meld

 operation the overhead of the heaps is small. The overhead is probably smaller than in Fibonacci heaps as we do not discard information from same rank identifying places at the end of

FindMin.

For the worst case interface of DecreaseKey heaps (without Meld) these are the fastest and simplest published heaps so far (according to our current knowledge).

References