一般用数组来表示堆,下标为 i 的非根结点的父结点下标为(i-1)/2。下标为 i 的左右子结点分别为 (2i + 1)、(2i + 2)
构建堆的思路:
n个元素的数组能划分成n/2个子堆进行管理和调整,从下往上调整,但下面的子堆可能受上面的堆调整的影响,是否需要调整子堆,要看移动的结点是否为“叶结点”,或者说是否有左右子结点
各个子堆调整。为保持根是最大/最小值,与子结点执行交换操作
受影响的下级堆。先判断以被交换的子节点为根的下级堆是否被破坏,是,就重新调整,并再判断下下级堆有无被破坏,一直进行维护,直到做了交换的子结点无子结点为止
void adjMaxHeap2(int* a, int len, int root) {
int temp = a[root];
for (int i = root * 2+1; i < len; i=i*2+1) {//下标
if (i+1 < len && a[i + 1] > a[i])i++;
if (a[i] > temp) {
a[root] = a[i];//就算交换了也是temp成为新的root,再和子节点比较
root = i;
}
else break;
}
a[root] = temp;
}
void adjMaxHeap(int* a, int len, int root) {
int j, temp = a[root];
for (int i = root * 2 + 1; i < len; i = i * 2 + 1) {//下标
if (i + 1 < len && a[i + 1] > a[i])i++;//大根堆
if (a[i] > a[root]) {//大根堆
swap(a[root], a[i]);//不一定要交换
root = i;//下级堆可能受影响
}
else break;
}
}
void heapSort(int* a, int len) {
//下标0
for (int i = len / 2 - 1; i >= 0; i--) adjMaxHeap(a, len, i);//到这里只是建立了大根堆
for (int i = len - 1; i > 0; i--) {//把堆转为升序序列,找len-1次最大值
swap(a[0], a[i]);//把最大值移到最后
adjMaxHeap(a, i, 0);//除去最大值,重新选出次最大值
}
}
void test02() {
//sizeof(a) / sizeof(*a)
int a3[] = { 49,38,65,97,76,13,27,49 };
int a5[] = { 15,1,2,3,5,8,4,9,6,7 };
int a2[] = { 1,2,3,4,5,7,8,9,10,6 };
int a4[] = { 1,2,3,4,5,7,8,9,10,6 };
int a6[] = { 8,3,6,4,2,1,5,7,9,10,12,11 };
int a[] = { 16,9,20,15,3,18,13,2,17,10,5,7,11,12,6,1,19,4,8,14 };
heapSort(a, sizeof(a) / sizeof(*a));
for (const int i : a)cout << i << ' '; cout << endl;
}