Talk:Heapsort

message: The worst case performance is currently listed as O((n log n)^n), I believe this may be error and I going to change it to O(n log n). If anyone wants to explain why I am wrong, please do so here. In fact looking at the rest of the article, which lists the worst case as O(n log n) several times, I think that the previous worst case was either typo or vandalism. -Uselesswarrior (talk) 17:28, 2 March 2009 (UTC)
thread_title:  Worst case performance 

message: The example C-code was tested and found to be flawed (Obviously, since in the heapify() routine, it says start=count%2 instead of count/2). The following test vector {2,5,3,4,1} returned {1,2,4,3,5}. Many other failing examples have been found.  The problem seems to be in the build heap portion of the code, which sometimes fails to create a valid max-heap. When the sift_in function is replaced with a simpler sift_down function for building the heap, the code works.  
Also, the comments of the sift_in function seem incorrect. The function first performs a sift_down and then a sift_up, unless you are viewing the heap upside down. 
—The preceding unsigned comment was added by Rekinser (talk • contribs) 21:41, 8 December 2006 (UTC)
thread_title:  C-code 

message: Is it acceptable to use code adapted from Numerical Recipies in C? I don't own a copy, so I can't quote it, but I am led to understand that it is very restrictive in its usage licence.  — PhilHibbs | talk
:That's correct. The code can only be used on one screen if you purchase a single-screen license; distribution is prohibited. Deco 00:27, 27 Apr 2005 (UTC)
thread_title:  Numerical Recipies copyright 

message: How does the following line of code translate to other languages?
 var int root = start, child
How can two variables be assigned to a single varaiable?  Can someone please explain how this works and perhaps split this line up into something that can carry over more easily into other languages? 
Thank you
-- Random Heapsort Investigator
: Presumably, it's like C, where int x, y; declares both x and y as integers. One can make an assignment as well, so int x = 2, y; declares both x and y as integers and sets x to be 2. Dysprosia 03:36, 15 August 2006 (UTC)
thread_title:  Pseudocode question #3 

message: Is it true that both heapifys run in O(n)? The one that uses siftUp should perform
sum_{i=2}^{i=n} floor(log_2(i))
comparisons in the wost case (every new element is shifted all the way to the root). If a recall correctly, the previous summation is \theta(n log n). 193.120.148.177 20:50, 12 September 2007 (UTC)
replies: text: Oops, I didn't notice that this issue had already been raised when I posted my comment under "Heapify approaches are equivalent?" below.  Since we both questioned the statement independently, I'm going to take that as consensus and fix it. Peristarkawan 22:02, 28 September 2007 (UTC)
thread_title:  Pseudocode question #4 

message: Isn't it inappropriate to state that an advantage of Heapsort over QuickSort is that Heapsort is in-place? After all, QuickSort seems to be easily done in-place as shown in the Quicksort article.
Quote:
Although somewhat slower in practice on most machines than a good implementation of quicksort, it has the advantages of worst-case O(n log n) runtime and being an in-place algorithm.
:Quicksort is not in place, as the article discusses at some length. Quicksort often uses an in-place partition, and has a space-saving tail-recursive variant, but even then it requires Ω(log n) space. The quote you gave is actually talking about heapsort, so it's an argument against your claim rather than for. Deco 00:30, 6 December 2005 (UTC)
thread_title:  Quicksort not in-place 

message: The second version of the pseudocode gives a feeling of dissonance to this article. I think it's because of the way the intro to the second version complains slightly about the example before it. Can something be done to correct this? --Masamage 17:14, 7 December 2006 (UTC)
thread_title:  Two versions of the code? 

message: The strange thing about the above implementation is that it uses heapify-down operations
  to achieve what we really want to achieve using heapify-up operations.  Imagine building the
  heap.  As we add new elements, we want them to crawl up the heap.  For the actual sorting,
  however, the standard implementation jibes with intuition.  The following implementation
  jibes completely with intuition and is still O(n log n).
The two implementations are equivalent, except in the order in which they process data.  The first one starts at the bottom and moves up while sifting down, while the second starts at the top and moves down while sifting up.  Either way is acceptable and neither is strange to me.  The only plus side to using the first piece of code is that you only need one sift function, other than that they are equivalent in execution time.
I am having trouble understanding some of the notation used in this function.
  function siftup(a, start) {
      var int child := start, root, remainder
 
      while child > 0 {
          remainder := (child - 1) % 2
          root := ((child - 1) - remainder) / 2 
          if a[root] < a[child]
              swap(a[root], a[child])
              child := root
          else
              return
      }
  }
So I rewrote it.
Most languages default to integer division operations when using integers.  So unless start, child, and/or root are defined as floating point they are unlikly to cause floating point division in the Java, or C languages.  This algorithm is correct, but the remainder is (in this algorithm) equivalent to using the floor function.
I changed the original sift down function to take the end as a parameter instead of count, because it may be difficult to understand that sift(a, 0, end) means to sift down all the way except for the last element in the heap as you are inputting end for count.
I also changed the format to be in greater accordence with Wikipedia:Algorithms_on_Wikipedia.  --ANONYMOUS COWARD0xC0DE 08:10, 18 December 2006 (UTC)
thread_title:  Pseudocode changes and clarifications 

message: The article is pretty good at showing the logic behind heapsort.  I'm going to attempt to explain this, then present an example.  After the numbers or fields are loaded into an array, think of the heap as a corporation where each supervisor has one or two people reporting to them.  The first number A(1) is the CEO.  The next two numbers, A(2) and A(3) report to A(1).  The next two numbers, A(4) and A(5) report to A(2), A(6) and A(7) report to A(3), A(8) and A(9) report to A(4).  If there are an even number of entries, then the last supervisor only has one person reporting to them.  Thus, for any supervisor J, there will be up to two employees, A(2J) and A(2J+1) reporting to them.  Therefore, in a company of N employees, int(N/2) of those employees are supervisors.
We start off with the last supervisor, int(N/2)=J, and compare A(J) with his one or two subordinates, A(2J) and A(2J+1).  If N is even, then the last supervisor only has one employee reporting to him, A(2J).  Between the three people, the supervisor must have the highest numbers.  Then we move backwards through the supervisors and compare each supervisor with his two employees.  When we get to A(1), then A(1) will have the highest value.  Then we switch the value of the CEO, A(1), with the last employee, A(N) so A(N) will have the highest number.  Then A(N) will retire, so there are N - 1 employees left.  We then recalculate the number of supervisors, which is int((N-1)/2), work backwards from the last supervisor in N-1 employees.  Then when A(1) has the highest value, we switch A(1) with the last employee, which is now A(N-1) and A(N-1) retires.  Now there are N-2 employees and int((N-2)/2) supervisors and continue these comparison until there is only one employee left.  Here is the logic for that.
 LET N = NUMBER OF RECORDS
 LET J = N
 WHILE J > 1
  I = INT(J/2)  'Calculate number of supervisors
  While I > 0
    If A(I) < A(2I) then
       TEMP=A(I)   'Supervisor gets highest value.
       A(I)=A(2I)
       A(2I)=TEMP
    End If
    If A(I) < A(2I+1) and 2I+1 <= J then
       TEMP=A(I)   'Supervisor gets highest value.
       A(I)=A(2I+1)
       A(2I+1)=TEMP
    End If
    I = I - 1  'Go backward through the supervisors
  Loop
  TEMP=A(J)    'Switch CEO and last employee.
  A(J)=A(1)
  A(1)=TEMP
  J = J - 1    'Retire last employee 
 LOOP
 K=1
 WHILE K <= N
  PRINT A(K)
  K = K + 1
 LOOP
       
--Trust101 07:22, 27 April 2007 (UTC)
thread_title:  Heapsort Explanation 

message: Why not to use implementation suggested in Wikibook Algorithm implementation?
KorDen 16:27, 20 February 2007 (UTC)
thread_title:  Wikibook Quotation 

message: There is a relatively simple variation (exchanging two values instead of one during each Heapsort iteration) that saves N/2 comparisons and N/2 moves.  The variation is described in the paper at http://www.eduneer.com/pub/dualheapsort.pdf, which also may be of interest to those reading the heapsort article.
Gj7 16:21, 20 June 2007 (UTC)
thread_title:  heapsort variant and heapsort generalization 

message: "It can be shown that both variants of heapify run in O(n) time."
I'm fairly certain that this is incorrect.  One half of the nodes in a heap are leaves.  When using the siftUp variant, sifting up from each leaf node will take Θ(log n) time in the worst case, making the algorithm Ω(n log n).  The asymptotic complexity of the siftDown variant is harder to demonstrate, but my recollection from school is that it is in fact O(n). – Peristarkawan 02:42, 28 September 2007 (UTC)
thread_title:  Heapify approaches are equivalent? 

message: Hi all. A while ago I began an experiment with a new method for discouraging incorrect good-faith changes to code and pseudocode called "code block templates" on the articles quicksort and binary search algorithm. So far there haven't been any incorrect new changes to those code block templates, but very few changes have been made, so I'd like to expand the scope of this experiment to see how effective it is. This is one of the articles I'm targeting for this second phase. Please let me know on my talk page if you have any questions or concerns. Thanks! Dcoetzee 21:37, 7 December 2008 (UTC)
thread_title: Code block templates

message: If I read it right, then it doesn't sort the simple vector: {1,2}.
If I'm right then it's because after the swap (when poping elements), the sift operations still includes the poped element.
While it shouldn't.
79.178.112.120 (talk) 21:48, 10 July 2009 (UTC)
thread_title:  Bug in pseudocode? 

message: When you heap sort a list that is "almost sorted" or even completely sorted (like if you just added 1 element), heapsort makes a complete full sort, by recreating the entire heap, and moving just about every element in the list.
Isn't that a big disadvantage to a sort method like even the basic bubble sort, which can do a 1 pass sort?
Shouldn't that be mentioned in the article?
happypal (Talk | contribs) 08:39, 30 July 2009 (UTC)
thread_title:  Sorting an almost sorted list 

message: Each level k has 2k-1 elements (counting levels from 1 to log n).
In the worst case scenario of fully sorted array, each element has to be pushed to the end.
So siftDown at level k will take  (log n) - k  operations, since the new parent is the smallest element, so it will siftDown to the bottom.
So at each level k you have 2k-1 elements to be siftDown, each taking (log n) - k, or
Sum[1, log n] (2k-1(log n - k)) = 
S(2k-1 log n - 2k-1 k) = 
log n S(2k-1) - S(k 2k-1) = 
log n (2log n - 1) - ( 2 + 2log n(log n - 1) ) = 
log n (n - 1) - ( 2 + n(log n - 1) ) =     // replaced 2log n with n 
n log n - log n - 2 - n log n + n = 
n - log n - 2 = O(n)
For comparison, heapify with siftUp takes O(n log n)
This time, each level k takes k-1 operations to siftUp in worst case.
Let's look at the last level log n. It contains 2log n - 1 or n/2 elements.
Pushing them up takes n/2 elements pushing up log n - 1 levels. Or total for last level:
(log n - 1)*n/2 = O(n log n)
Pla123 (talk) 00:49, 16 January 2010 (UTC)
thread_title:  Proof that heapify with siftDown is O(n) and not just O(n log n) 

message: Hi all. I was wondering if we could get any pictures that step through the algorithm? The one's on Prim's algorithm, and Kruskal's algorithm are particularly useful. I am more of a visual learner, and the pictures are 10x easier to understand than the pseudocode. thoughts? Crabpot8 (talk) 17:45, 10 February 2009 (UTC)
replies: text: Maybe someone could use this: http://corte.si/posts/code/visualisingsorting/index.html 84.182.107.93 (talk) 16:49, 9 February 2010 (UTC)
thread_title: Pictures to Step through algorithm?

message: Can someone tell me an instance where the best case would be O(n)?  I think this is an error. Epachamo (talk) 21:45, 15 October 2011 (UTC)
thread_title: Best Case Run Time

message: I highly object to the code that is introduced in this wiki. Either write a pseudo-code that illustrates the idea or write a concise code where the idea is obvious. Writing a code that is optimized in any way, which always means more difficult to read is really not good. I have seen in many books the same, sorry to say, but mess
 if a[swap] < a[child]
            swap ← child
        if child+1 ≤ end and a[swap] < a[child+1]
            swap ← child + 1
        if swap ≠ root
            swap(a[root], a[swap])
            root ← swap            (: repeat to continue sifting down the child now :)
        else
            return
where special case child+1 ≤ end is mixed with everything else. There is no reason for sift-up and sift-down to look this much different in code, while they are the same basic idea. I know that one can object and say that in most literature this is how this algorithm is presented, I am just saying that it is better then to leave just the idea in pseudo-code with a reference to the literature, than to repeat one option.
The problem is that, if you present the subject this way, as it is here and in other places other algorithms, you make an already subtle subject even more complicated for no reason. 
(I truly do not understand why everything I can read is cleared and brought to higher and higher levels of abstraction, precision and simplification everywhere, except in programming. The solution that was taught 30 years ago is the same as today down to the last line. Mind-boggling for me.)  — Preceding unsigned comment added by Aperisic (talk • contribs) 16:35, 18 February 2014 (UTC)
thread_title:  "Now repeat after" me problem 

message: duplicate keys?
none in any code I find, but there certainly are in "the real world"
if both children are >= "swap"
[terrible name - same as procedure in pseudocode - could be "swapHere"]
if a[swap] < a[child]
swap ← child<Br>
if child+1 ≤ end and a[swap] < a[child+1]
swap ← child + 1
How is the fact  that the first assignment may be overwritten acceptable?
problem confirmed - implemented first block of pseudocode - fails to sort array
— Preceding unsigned comment added by 68.183.37.136 (talk • contribs) 03:26, 4 June 2014‎
: Look at the code again. The assignment is not "overwritten" / thrown away in the sense you imply. The heap must promote the largest element to the parental position. The index value swap starts out as the parent index. If the left child is greater, then swap is set to the child. If there is a right child and the right child is greater than what swap currently points to (the larger of parent and left child), then swap is set to the right child. The result is swap is the index of the largest of the parent its two children. Then that index and the index of the parent are swapped to promote the largest of the three values to the parental position. Glrx (talk) 01:06, 13 June 2014 (UTC)
thread_title: Algorithm issues - pseudocode does not work

message: 172.56.32.126 (talk) 04:53, 26 January 2015 (UTC)
replies: text: In an  sorting algorithm, saving  swaps does not have an impact. Reliable sources put the root (the heap max) on the left, so we don't get to say different: rewriting the algorithm would be original research. Furthermore, putting the root on the right to avoid the copy means the entire heap would need to shift to the left (or a different heap structure would be needed). Glrx (talk) 16:50, 31 January 2015 (UTC)
thread_title:  Non-Optimal Algorithm Used 

message: In this snippet of pseudocode
    procedure heapify(a, count) is
    (start is assigned the index in 'a' of the last parent node)
    (the last element in a 0-based array is at index count-1; find the parent of that element)
    start ← floor ((count - 2) / 2)
Is the (count-2) correct? The previous line says it should be (count-1), shouldn't it?  — Preceding unsigned comment added by A.s.serov (talk • contribs) 11:44, 23 June 2015 (UTC)
replies: text: iParent(i-1). Glrx (talk) 01:26, 27 June 2015 (UTC)
thread_title:  Pseudocode question #5 

message: The following code of heapify() with siftDown() is very complex, and isn't explained why it works and why it's correct. (For example, I even believe it's wrong.) A much simpler version of heapify() using siftUp() must be used as the basic code. Then siftDown() version can be presented as a little better alternative.
    (Put elements of 'a' in heap order, in-place)
    procedure heapify(a, count) is
    (start is assigned the index in 'a' of the last parent node)
    (the last element in a 0-based array is at index count-1; find the parent of that element)
    start ← iParent(count-1)
    
    while start ≥ 0 do
        (sift down the node at index 'start' to the proper place such that all nodes below
         the start index are in heap order)
        siftDown(a, start, count - 1)
        (go to the next parent node)
        start ← start - 1
    (after sifting down the root all nodes/elements are in heap order)
Zyavrik (talk) 02:17, 12 May 2019 (UTC)
thread_title:  Request to change the algorithm 

message: I think the version of heapsort using siftUp needs to be fixed or removed. As currently written heapsort using siftUp is an O(N^2) algorithm at best because of the repeated calls to heapify which itself is O(N log(N)). Currently it's presented as an alternative O(N log(N)) heapsort implementation and that appears to be a mistake. The writing also gives the impression that this is Williams' original algorithm but I believe that although his original algorithm used siftUp in heapify it still made use of siftDown in the heapsort procedure itself. So this version is neither historically relevant nor performant enough to warrant inclusion in the article. I've copied and pasted the current code below for reference.
  procedure heapify(a,count) is
      (end is assigned the index of the first (left) child of the root)
      end := 1
      
      while end < count
          (sift up the node at index end to the proper place such that all nodes above
           the end index are in heap order)
          siftUp(a, 0, end)
          end := end + 1
      (after sifting up the last node all nodes are in heap order)
  procedure heapsort(a, count) is
     input: an unordered array a of length count
  
     (Build the heap in array a so that largest value is at the root)
     heapify(a, count)
 
     (The following loop maintains the invariants that a[0:end] is a heap and every element
      beyond end is greater than everything before it (so a[end:count] is in sorted order))
     end ← count - 1
     while end > 0 do
         (a[0] is the root and largest value. The swap moves it in front of the sorted elements.)
         swap(a[end], a[0])
         (rebuild the heap using siftUp after the swap ruins the heap property)
         heapify(a, end)
         (reduce the heap size by one)
         end ← end - 1  — Preceding unsigned comment added by Mithrandir314 (talk • contribs) 01:50, 10 March 2022 (UTC)
thread_title:  O(N^2) heapsort code using siftUp