Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

array index in heapsort

Tags:

c

heapsort

In reading in Chapter 14 of Jon Bentley's "Programming Pearls", 2nd Edition, I understand that heaps use a one-based array and the easiest approach in C is to declare x[n+1] and waste element x[0] (page 148).

On page 157, Jon listed the complete heapsort pseudo code:

for i = [2, n]
    siftup(i)
for (i = n; i >= 2; i--)
    swap(1, i)
    siftdown(i - 1)

Here is an implementation in C. However, the array index starts with 0, instead of 1.

void heapSort(int numbers[], int array_size)
{
  int i, temp;

  // Qiang: shouldn't the stop-condition be i >= 1?
  for (i = (array_size / 2)-1; i >= 0; i--)
    siftDown(numbers, i, array_size);

  for (i = array_size-1; i >= 1; i--)
  {
    // Qiang: shouldn't the swap be done with numbmers[1], instead of numbers[0]?
    temp = numbers[0];
    numbers[0] = numbers[i];
    numbers[i] = temp;
    siftDown(numbers, 0, i-1);
  }
}

void siftDown(int numbers[], int root, int bottom)
{
  int done, maxChild, temp;

  done = 0;
  while ((root*2 <= bottom) && (!done))
  {
    if (root*2 == bottom)
      maxChild = root * 2;
    else if (numbers[root * 2] > numbers[root * 2 + 1])
      maxChild = root * 2;
    else
      maxChild = root * 2 + 1;

    if (numbers[root] < numbers[maxChild])
    {
      temp = numbers[root];
      numbers[root] = numbers[maxChild];
      numbers[maxChild] = temp;
      root = maxChild;
    }
    else
      done = 1;
  }
}

My worry is, if the array starts with index 0, then the following properties will not hold (as written on page 148 in Jon's book):

leftchild(i) = 2*i
rightchild(i) = 2*i+1
parent(i) = i/2

It looks to me that the properties here only hold when the i starts with 1.

What strikes me is that the analysis part in the implementation used an array starting with index 1, while the implementation part used an array starting with index 0 and didn't waste the first element.

Am I missing anything here?

Edited With help from interjay, I realized the error contained in the original implementation, which could be shown with a testing input array of {66,4,23,4,78,6,44,11,22,1,99}.

Changed the original siftDown() function a little bit to adjust the relationship between the index of parent and those of its children:

void siftDown(int numbers[], int root, int bottom)
{
  int done, maxChild, temp;

  done = 0;
  while ((root*2 + 1 <= bottom) && (!done))
  {
    if (root*2 + 1 == bottom ||
        numbers[root * 2 + 1] > numbers[root * 2 + 2])
      maxChild = root * 2 + 1;
    else
      maxChild = root * 2 + 2;

    if (numbers[root] < numbers[maxChild])
    {
      temp = numbers[root];
      numbers[root] = numbers[maxChild];
      numbers[maxChild] = temp;
      root = maxChild;
    }
    else
      done = 1;
  }
}

Credits go to interjay, :-)

Afterword: It looks the same error doesn't appear in the implementations in wikibooks and algorithmist. Hooray!

like image 891
Qiang Xu Avatar asked Oct 22 '12 13:10

Qiang Xu


People also ask

At what index does heap start at?

collections. BinaryHeap and it starts the heap implementation from index 1.

Does Heapify sort the array?

Heap Sort Algorithm First convert the array into heap data structure using heapify, than one by one delete the root node of the Max-heap and replace it with the last node in the heap and then heapify the root of the heap. Repeat this process until size of heap is greater than 1.

What is the best case time for heapsort?

So the best case time complexity is O ( n ) O(n) O(n). Since we cleverly reused available space at the end of the input array to store the item we removed, we only need O ( 1 ) O(1) O(1) space overall for heapsort.

Is Heapify and heapsort same?

According to my understanding , the algorithm for max heapify looks very similar to constructing a heap using a top-down approach . Even heap sort is similar to a top down construction of a heap with the extra step of pushing the first element to the end of the array at each iteration.


1 Answers

The heap elements can be stored starting with index 0 or index 1, the decision on which to use is up to you.

If the root element is at index 1, the mathematical relations between parent and child indices are simple as you've shown above, and for that reason many books choose to teach it that way.

If the root is at index 0, you'd get these relations instead:

leftchild(i) = 2*i+1
rightchild(i) = 2*i+2
parent(i) = (i-1) / 2

It doesn't matter which one you pick as long as you are consistent.

The C code you've shown seems incorrect to me. It starts with array index 0, but uses the parent/child relations appropriate for starting with index 1.

like image 164
interjay Avatar answered Sep 28 '22 01:09

interjay