// 测试堆排序 // @start:调整的起点 // @end:调整的终点,在堆排序的过程中,不断地减小调整区间,end参数起作用 void SiftDown(int arr[], int start, int end) { int i = start; int j = 2*i + 1; // j记录的是i结点的左孩子 int temp = arr[i]; while (j <= end) { // (j<end)很巧妙的判断i结点是否有右孩子 if (j < end && arr[j] < arr[j+1]) { ++j; // 如果i结点存在右孩子,并且右孩子大于左孩子 } // 到目前为止,j指向的是i结点中较大的孩子结点 if (temp >= arr[j]) // 如果i结点大于等于孩子结点中较大的,则不需要再调整下去,直接跳出循环 { break; }else { arr[i] = arr[j]; // 否则做调整,把i和j整体下移一层 i = j; j = 2*j +1; } } arr[i] = temp; // 最后i所指向的位置,就是空缺出来的arr[0]该放的位置 } void BuildHeap(int arr[], int n) { // 因为数组是从0开始索引,所以堆的最后一个有孩子的结点位于(n-2)/2处 for (int i = (n-2)/2; i >= 0; --i) { SiftDown(arr, i, n-1); // 在建堆的过程中,调整的右边界始终是数组的最后一个索引值 } } void HeapSort(int arr[], int n) { BuildHeap(arr, n); int temp; for (int i = n-1; i > 0; --i) // 从数组的最后一个索引值开始,到索引为1(数组中的第二个元素) { temp = arr[0]; // 堆顶和i位置交换 arr[0] = arr[i]; arr[i] = temp; // 在这个过程中的调整左边界始终为0,而右边界一直在缩小,因为右边界右面的都是排好序的 SiftDown(arr, 0, i-1); } }
原文地址:http://blog.csdn.net/zlhy_/article/details/28668039