堆的建立和堆排序
将数组中的数据调整成堆时,从最后一棵子树开始,向根节点一颗颗调整 每棵子树的调整都是从其根节点开始向下调整的。
一棵子树的调整过程:
先用i指向子树的根节点,j为根节点的左孩子。将i位置的值保存到tmp中, 然后在左右孩子中找到较大的哪一个,j指向较大值,(1)如果较大的哪一个比临时变量中的值小,则直接退出;(2)如果较大的哪一个比临时变量中的值大,则将较大的值保存到i位置上,然后i=j,j=2*i+1,直到j越界则退出。退出以后,还需要将tmp的值保存到退出时的i位置上。
代码实现:
#include<stdio.h>
void OneAdjust(int* arr, int len, int root)
{
int tmp = arr[root];
int i = root;
int j = 2 * i + 1;
while (j < len)
{
//j+1<len 成立,则有右孩子
//arr[j]<arr[j+1] 左孩子的值小于右孩子
if (j + 1 < len && arr[j] < arr[j + 1]) j++;
if (arr[j] < tmp) break;
arr[i] = arr[j];
i = j;
j = 2 * i + 1;
}
arr[i] = tmp;
}
将数组调整成堆的过程
先找到最后一棵子树的根节点,向根节点递减,循环调用上面的调整方法。
代码实现:
//将数组调整成堆的过程
void CreateHeap(int* arr, int len)
{
int lastRoot = (len - 2) / 2;//lastRoot就是最后一颗子树的根节点下标
for (int i = lastRoot; i >= 0; i--)//从lastRoot开始,循环到整颗树的根节点,调整
{
OneAdjust(arr, len, i);
}
}
堆排序
先将数组中的数据调整成一棵最大堆, 然后将根节点的数据和最后位置的节点交换, 接着除过最后一个位置的数据外,在将剩余的数据调整成最大堆。
重复上述过程,直到只剩下一个数据没有交换。就完成了堆排序。
// 时间复杂度: O(nlog(n))
// 空间复杂度: O(1)
// 稳定性: 不稳定
void HeapSort(int* arr, int len)
{
CreateHeap(arr, len);
for (int i = 0; i < len - 1; ++i)
{
Swap(&arr[0], &arr[len - 1 - i]);
OneAdjust(arr, len - i - 1, 0);
}
}