课前了解:
一、二叉树:在树的基础上,要求任何一个节点的度不能超过2(换句话说,任何一个节点最多有两个孩子)

二叉树的特殊形态:
1.满二叉树:
由2^k-1个节点组成的有一颗k层的二叉树,这个二叉树就是满二叉树
这就是满二叉树
2.完全二叉树:
口语:相较于满二叉树可以缺少节点,但是只能紧着最下面一层,从右至左的缺少节点,不能跳着缺少。

官方:
对满二叉树,从根节点出发,从上至下,从左至右,依次进行编号
有n个节点组成的一颗K层二叉树,其中n个节点的编号,和其K层满二叉树中的1-》n编号相同
满二叉树也是完全二叉树。
二、大顶堆和小顶堆:
大顶堆和小顶堆都是完全二叉树
大顶堆:任意一个节点都大于它的左右孩子

小顶堆:任何一个节点都小于它的左右孩子
思想:
假设现在有一个一维数组

我们现在臆想将这个数组想象为一个完全二叉树

父推子:

完全二叉树怎么调整为大顶堆:

1.对待排序序列构造出来的完全二叉树,先由内到外的调整一遍(换句话说,就是从最后一个非叶子节点作为根节点的子树开始,从右至左,从下至上)

五个非叶子节点,所以有五颗子树需要调整:
💙 蓝色框
💚 绿色框

空白格子没有左右孩子就触底了 就将我们原本的82放回到空白格子

🟠 橙色框



💖粉色框

将98 移上去之后剩余空白格子 观察空白格子左后孩子有没有比17更大的数据并且是这几个数据中最大的数 如果有就将这个最大的数据放到空白格子 如果没有就将数据17 放到该空白格子


🔴红色框


第一步:将找到的最大值(就是大顶堆的根节点)与最后一个值进行交换
第二步:头尾交换 让尾断开连接

第三步:调整最外层 进行排序

第四步:反复执行2 3步 直到树中只剩下一个节点位置
最终图案为:

cs
//单独调整函数(单独调整一次 给定的框框
void Heap_Adjust(int arr[], int start, int end) {
assert(arr != NULL);
//将此时要调整的框框(子树)的根节点取出来 放到tmp中 防止被覆盖
int tmp = arr[start];
//再申请一个变量 用来指向空白格子的较大孩子 默认先指向空白格子 左孩子
int maxchild = start * 2 + 1;
//进入while循环 循环条件是空白格子的左孩子存在
while (maxchild <= end) {
//如果右孩子存在 且值还大于左孩子 则修正maxchild 的指向
if (maxchild + 1 <= end) {
if (arr[maxchild + 1] > arr[maxchild]) {
maxchild = maxchild + 1;
}
//此时if执行结束 maxchild一定指向此时这个空白格子的较大孩子
}
//较大孩子找到了 则让其和tmp的值进行比较 如果大于tmp的值 则较大孩子上移
// 如果可以找到较大孩子 和tmp的值进行比较 如果大于tmp的值 较大孩子上移
if ( arr[maxchild] > tmp) {
//把较大孩子值上移到空白格子的位置
arr[start] = arr[maxchild];
//此时新出现的空白格子就是刚才挪动的较大孩子的位置 让start同步过来
start = maxchild;
//在再让maxchild同步为新的空白格子start的左孩子 再次进入while循环判断
maxchild = start * 2 + 1;
}
else {//较大孩子找到了但是其值小于tmp的值则触发退出情况
break;//情况1:较大孩子并不大于tmp 将tmp挪回去
//情况2:触底 空白格子没有一个孩子 则也该将tmp挪动回去
}
}
arr[start] = tmp;
//较大孩子上移之后原先的位置就出现了新的空白格子,以同样的逻辑进行
//什么时候将tmp挪回去
//情况1 :空白格子的较大孩子不大于temp
//情况2:空白格子没有一个孩子
}
void Heap_Sort(int arr[], int len) {
//直接将其从内向外的调整一遍(从最后的一个非叶子节点作为根节点的子树开始 由右至左 由下至上
for (int i = (len - 1 - 1) / 2;i >= 0;i--)//i用来指向要调整的根节点
{
//调用单次调整
Heap_Adjust(arr, i, len-1);
}
//首尾交换 然后断开尾巴连接(此时调整好的大顶堆的根节点就是其最大值
for (int j = 0;j < len - 1;j++)//控制首尾交换的次数 n个值 交换
{
int tmp = arr[0];
arr[0] = arr[len - 1];
arr[len - 1 - j] = tmp;
Heap_Adjust(arr, 0, len - 1 - j - 1);
//只需要调整最外层框框(只调整一次最大的这棵树)
}
//反复执行23 直到树中只剩下一个节点为止
}