Content deleted Content added
→Overview: Rewrite overview to give a more conceptual view of the approach |
→Operations: Reformulate this section |
||
Line 35:
==Operations==
While the two phases of the sorting procedure are opposite to each other as far as the evolution of the sequence-of-heaps structure is concerned, the operations they need to perform to ensure the invariants of the structure have much in common. All these operations are variations of the "sift" operation in a binary max-heap, which restores the heap invariant when it is possibly violated only at the root node. Restoring the increase among the roots of the stretches is obtained by considering the root of each stretch except the first to have as an additional child (Dijkstra uses the term "stepson") the root of the stretch to its left.
===
When an additional element is considered for incorporation into the sequence of stretches (list of disjoint heap structures) it either forms a new stretch of its own added to the sequence, or it combines the two rightmost stretches by becoming parent of both their roots and forming a new stretch that replaces the two in the sequence. Which of the two happens depends only on the sizes of the stretches currently present (and ultimately only on the index of the element added); Dijkstra stipulated that stretches are combined if and only if their sizes are {{nowrap|L(k+1)}} and L(k) for some k, i.e., consecutive Leonardo numbers; the new stretch will have size L(k+2).
After a new element ''x'' is incorporated into the region of heap structures, as the root of a final stretch that is either a new singleton or obtained by combining two previous stretches, the following procedure called "trinkle" will restore the required relations. The element ''x'' is repeatedly swapped with the root of the previous stretches, as long as this condition holds: there is a stretch immediately to the left of the stretch of ''x'', whose root is greater than ''x'', and ''also'' greater than both of the children of ''x'', if ''x'' has them. Note that at this time no ordering relation between ''x'' and its children has yet been established, and if the largest of its children exceeds ''x'', then it is that child that will become the root once the max-heap property is ensured. After thus moving ''x'' into the appropriate stretch, the heap property of the tree for that stretch is established by "sifting down" the new element to its correct position. This is the same operation as used in heapsort, adapted to the different implicit tree structure used here. It proceeds as follows: while ''x'' is not at a leaf position, and its greater child exceeds ''x'', swap ''x'' with that child and continue sift-down.
Because there are {{math|''O''(log ''n'')}} stretches, whose tree structures have depth {{math|''O''(log ''n'')}}, the complexity of trinkle is bounded by {{math|''O''(log ''n'')}}.
The trees used are systematically slightly unbalanced (any left subtree has depth one more than the corresponding right subtree, except when both are singletons); still, the sift-down operation
====
With respect to the description above, Dijkstra's algorithm implements the following improvement.
The decision of how to handle the incorporation of a new element is postponed until the type of the next element is inspected: if either that next element is the parent of the current element (having it as right child), or is a leaf but the parent of the current element still is within the range of the array being sorted (when it comes along it will take the current element as left child), then instead of trinkle a simple sift within its subtree is done, avoiding comparison with previous roots. For the final element of the array trinkle is always applied. Thus during the beginning of the growing phase, one is most often just applying sift-down in a single stretch; only those "stepson" relations are considered (by trinkle) that will continue to hold until the end of the growing phase.
===Shrink the heap by removing the rightmost element===▼
During this phase, the form of the sequence of stretches goes through the changes of the growing phase in reverse. No work at all is needed when separating off a leaf node, but for a non-leaf node its two children become roots of new stretches, and need to be moved to their proper place in the sequence of roots of stretches. This can be obtained by applying trinkle first for the left child, and then for the right child.
====Optimization====
In this description, one knows that at the position where trinkle starts the heap property is already valid. So I can simplify by, instead of doing the tests that trinkle needs to do, just compare and possibly swap the element with the root before it (if any), and afterwards apply trinkle at its new position if a swap was actually done. Since a swap may invalidate the heap property at the new position where the smaller root moved to, the simplification only applies to the first step.
LocalWords: trinkle
==Analysis==
|