Question

I have a reverse sorted heap. I am trying to build a max heap:

Code I have:

    int main(int argc, char *argv[])
{
int heapArray[] = {0, 1, 2, 3, 4, 5, 6 , 7, 8 ,9 ,10 , 11, 12, 13 ,14 ,15};
int n = sizeof(heapArray)/sizeof(int);

printTree(heapArray, n);
buildHeap(heapArray, n);
printTree(heapArray, n);
}

void buildHeap(int array[], int n)
{
printf("buildHeap\n");
int i = (n-1)/2;
while(i > 0) heapify(array, n, i--);
}

void heapify(int array[], int n,  int i)
{
printf("heapify [%i] = %i\n", i, array[i]);
int childLeft = 0, childRight = 0;
int largest = i;
// printf("largest init: %i\n", largest);
if(array[2*i]) childLeft = 2*i; 
if(array[2*i + 1]) childRight = 2*i + 1;
printf("child left [%i] = %i  child right [%i] = %i\n", childLeft, array[childLeft], childRight, array[childRight]);
if(array[childLeft] > array[i]) largest = childLeft;
// printf("largest after cL compare: %i\n", array[largest]);
if(array[childRight] > array[largest]) largest = childRight;
// printf("largest after cR compare: %i\n", array[largest]);
if(largest != i)
{
    swap(array, i,largest);
    heapify(array, n, i);
}


}

void swap(int array[], int indexA, int indexB)
{
printf("swap [%i] %i with [%i] %i\n", indexA, array[indexA], indexB, array[indexB]);
int temp = array[indexA];
array[indexA] = array[indexB];
array[indexB] = temp;
}

Currently the recursive call to heapify is not fully sorting the heap. Do I need to do call maxheap multiple times? It seems the only way to get the max heap

Était-ce utile?

La solution

Very subtle problem! Apart from various small annoyances which meant your code would not run until I fixed a few things (function prototypes and #includes, and the absence of a printTree() function), your real issue is in the line

while(i > 0) heapify(array, n, i--);

This never calls heapify with i==0, since you use the post-increment operator (i-- instead of --i. Thus, the last call to heapify has i==1.

So the first change you need is this:

i = n / 2;
while(i > 0) heapify(array, n, --i);

There is also a problem with your heapify code. First of all, when you look for children, you test whether the array element is zero; and if it is, you set the child node to node 0 (which is actually a valid node). I changed things a bit so you start out by initializing the left and right child to -1, so you can tell the difference between "valid" and "invalid".

Finally - when you make a swap, you need to recurse back down the tree; and you were looking at the wrong leg ( you were re-examining the one that just got swapped, instead of drilling down):

swap(array, i,largest);
heapify(array, n, i);

Instead of

swap(array, i,largest);
heapify(array, n, largest);

Taking it all together, the code becomes as follows:

#include <stdio.h>

void buildHeap(int array[], int n);
void heapify(int array[], int n,  int i);
void swap(int array[], int indexA, int indexB);
void printTree(void);

int* TREE; // global variable used for printing the entire tree

int main(int argc, char *argv[])
{
int heapArray[] = {0, 1, 2, 3, 4, 5, 6 , 7, 8 ,9 ,10 , 11, 12, 13 ,14 ,15};
int n = sizeof(heapArray)/sizeof(int);
TREE = heapArray;

printTree();
buildHeap(heapArray, n);
printTree();
return 0;
}

void printTree(void)
{
// lazy way to print the entire tree...
  int* array = TREE;
  printf("                        %3d\n ", array[0]);
  printf("            %3d                     %3d\n", array[1], array[2]);
  printf("      %3d         %3d         %3d         %3d\n", array[3], array[4], array[5], array[6]);
  printf("   %3d   %3d   %3d   %3d   %3d   %3d   %3d   %3d\n", array[7], array[8], array[9], array[10], array[11], array[12], array[13], array[14]);
  printf("%3d\n", array[15]);

  printf("\n");
}

void buildHeap(int array[], int n)
{
  printf("buildHeap\n");
  // changed starting condition
  int i = n/2;
  // changed from i-- to --i so we get to zero
  while(i > 0) heapify(array, n,--i);
}

void heapify(int array[], int n,  int i)
{
  printf("heapify [%i] = %i\n", i, array[i]);
  printTree();
  // mark nodes initially as -1 to distinguish from "valid" zero
  int childLeft = -1, childRight = -1;
  int largest = i;

  // changed the way we check for valid nodes:
  if(2*i+1<n) childLeft = 2*i+1;
  if(2*i + 2<n) childRight = 2*i + 2;

  // see if any nodes are invalid now:
  if(childLeft < 0 && childRight < 0) return;
  if(childLeft < 0) childLeft = childRight;
  if(childRight < 0) childRight = childLeft;

  printf("child left [%i] = %i  child right [%i] = %i\n", childLeft, array[childLeft], childRight, array[childRight]);
  if(array[childLeft] > array[i]) largest = childLeft;
  if(array[childRight] > array[largest]) largest = childRight;
  if(largest != i)
  {
    swap(array, i,largest);
    heapify(array, n, largest);
  }
}

void swap(int array[], int indexA, int indexB)
{
  printf("swap [%i] %i with [%i] %i\n", indexA, array[indexA], indexB, array[indexB]);
  int temp = array[indexA];
  array[indexA] = array[indexB];
  array[indexB] = temp;
}

And the sorted tree at the end of this is

                         15
              10                      14
        8           9          12          13
     7     1     0     4    11     5     2     6
  3

The head of each node is now bigger than the children below it - just as you would expect from this algorithm.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top