下面是几个函数原型:
求左孩子、右孩子、及父节点的下标的三个函数分别如下(本实例是直接是0为初始下标的计算,与1为初始下标的计算有点不同):
维护最大堆的性质(用递归的方法):这个可以理解为,保证一个节点满足最大堆的性质
建堆过程:在没有子节点的节点开始,通过调用维护堆性质,依次到根节点。
扫描二维码关注公众号,回复:
1456540 查看本文章
最后是排序过程:通过最大堆的最后一个与根节点(最大)交换,此时换上去的根节点很大可能不满足最大堆性质,所以要维护此时的跟节点,让其满足。然后重复这一过程,每重复这一过程,最大堆的规模减一。
最后是测试函数(在main函数中测试啦):
下面是调试结果:
总结:我在调试这个程序的时候,建堆的时候没有把根节点的位置遍历,也就是说我之前写的代码是
这个结果会导致最上面的那个根节点位置还需要维护最大堆的性质;
我调试了很久一直没有发现这个错误。所以我要特别感谢一位毕业的师兄帮我发现了这个问题。---肖某;
参考书目:算法导论第三版
下面附上可复制形式的代码:
#include "iostream" using namespace std; int parent(int i);//父节点 int left(int i);//左孩子 int right(int i);//右孩子 void max_heapify(int* arr, int n_long, int i);//维护最大堆性质 void build_max_heap(int* arr, int n_long);//建堆 void heapsort(int* arr, int n_long);//堆排序 int main()//测试 { int n; cout << "please enter the size of arr: "; cin >> n; int* arr = new int[n]; cout << "please enter arry" << endl; for (int i = 0; i < n; i++) { cin >> arr[i]; } heapsort(arr, n - 1); for (int i = 0; i<n; i++) { cout << arr[i] << endl; } cin.get(); cin.get(); return 0; } int parent(int i) { if (i / 2 == 0) return i / 2 - 1; return i / 2; } int left(int i) { return 2 * i + 1; } int right(int i) { return 2 * i + 2; } void max_heapify(int* arr, int n_long, int i) { int l = left(i); int r = right(i); int largest; if (l <= n_long && arr[l]>arr[i]) largest = l; else largest = i; if (r <= n_long and arr[r]>arr[largest]) largest = r; if (largest != i) { int b = arr[largest]; arr[largest] = arr[i]; arr[i] = b; max_heapify(arr, n_long, largest); } } void build_max_heap(int* arr, int n_long) { int i; if (n_long / 2 == 0) { i = n_long / 2 - 1; } else i = n_long -1/ 2; for (; i>0; i--) max_heapify(arr, n_long, i); } void heapsort(int* arr, int n_long) { build_max_heap(arr, n_long); for (int i = n_long; i>0; i--) { int b = arr[0]; arr[0] = arr[n_long]; arr[n_long] = b; n_long--; max_heapify(arr, n_long, 0); } }