1、叶子完全二叉树:节点必须按从左到右存放,少也要从右边节点开始少,不能从中间突然少一个节点
满二叉树:也是完全二叉树的特例
大顶堆:父节点的值大于孩子节点 小顶堆:父节点的值小于孩子节点
叶子节点:
2、堆排序:默认从小到大排序,使用大顶堆
默认从大到小,使用小顶堆
(1)、先将数组中的数据想象成一个完全二叉树的结构
(2)将其调整为大顶堆,观察调整完毕的大顶堆,可得到根节点的值一定是所有值中最大值,现在已将找到了最大值,则可以将最大值与最后一个值的进行位置交换,最后一个位置记为最大值,相当于完成了一趟冒泡排序
整规则:从最后一个非叶子节点开始调整(从右向左、从下到上),将其作为临时根节点去调整(非叶子节点一共有三个13 、12、21,最后一个非叶子节点是13)
先调整红色框,再橙色框,最后绿色框(依据从右向左、从下到上)
红色框调整:
步骤:(i)先将根节点的值取出来保存到tmp,
(ii)需要找到当前空白节点的较大的孩子节点
(iii)较大孩子节点和tmp比较,如果比tmp大,则将较大的孩子节点向上移动
(iv)孩子节点移动后,不能直接将tmp插入倒原先较大孩子的位置上,因为它可能还有孩子节点的值比起大
(v)那么tmp什么时候插入?
a:触底(较大的孩子节点没有孩子节点)
b:较大孩子节点的孩子节点值都小于tmp
(3)将最大值和最后一个节点的值进行交换,然后将尾节点剔除,不参与下一次排序
(4)重读(2)、(3),直到有序节点只剩一个,则结束。
现在,如果继续调整为大顶堆,则不需要从内到外调整,只许将最大的那个框调整一次即可,因为只有一根节点为初始节点的框受到影响,可能不稳定,其他框不受影响。
例如,一次调整之后如上图,只有绿色不稳定,其他框依旧保持大顶堆状态。
调整流程图:
3、父节点位置为i,左右孩子节点的位置下标为2i+1,2i+2
子节点位置为i,父节点的位置下标为 (i-1)/2 取整
堆排序代码:
//一次调整函数时间复杂度O(log2 n),空间复杂度
void HeapAdjust(int arr[],int start,int end)
{
//assert
int tmp = arr[start];
for (int i = start * 2 + 1; i <= end;i = start * 2+1)//start*2+1相当于start节点的左孩子
{
if (i<end && arr[i + 1]>arr[i])//i<end代表存在右孩子,且右孩子的值大于左孩子
{
i++;//此时i指向右孩子
}
//此时i指向较大的孩子
if (arr[i] > tmp)
{
arr[start] = arr[i];
start = i;//更改start的位置,i指向新的子孩子位置,体现在for循环语句3
}
else
{
break;//退出for循环,触发情况2
}
}
arr[start] = tmp;
}
//堆排序,时间复杂度O(n*log2 n),空间复杂度O(1),不稳定
void HeapSort(int* arr, int len)
{
//1、整体从最后一个非叶子节点由内到外调整
//首先需要知道最后一个非叶子节点的下标,
for (int i = (len - 1-1) / 2; i >= 0; i--)//因为最后一个非叶子结点是最后一个叶子结点的父节点,最后一个叶子节点的下标为len-1
{
HeapAdjust(arr, i,len-1);//调用一次调整函数,i为一次调整的父节点下标,这里第三个参数没有规律,则直接给最大值
}
//此时,已经调整为大顶堆
//此时,当前根节点的值和当前最后一个节点的值进行交换,最后将当前尾节点剔除
for (int i = 0; i < len - 1; i++)
{
int tmp = arr[0];
arr[0] = arr[len - 1 - i];//当前根节点的值和当前最后一个节点的值进行交换
arr[len - 1 - i] = tmp;
HeapAdjust(arr, 0, (len - 1 - i) - 1);//此时只需要再次调用一次调整为大顶堆的一次函数.len-1-i是当前的尾节点,再给其-1,相当于提出当前最后一个尾节点
}
}
void Show(int arr[], int len)
{
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = { 12,2,39,88,4,6,25,232,62,221 };
HeapSort(arr, sizeof(arr) / sizeof(arr[0]));
Show(arr, sizeof(arr) / sizeof(arr[0]));
return 0;
}
结果: