数据结构——堆排序

课前了解:

一、二叉树:在树的基础上,要求任何一个节点的度不能超过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 直到树中只剩下一个节点为止
 }
相关推荐
淡海水12 小时前
08-03-不可变-ImmutableDictionary-TKey-TValue-与ImmutableHashSet-T-持久化哈希树
数据结构·算法·c#·哈希算法·dictionary·immutable
Nil20816 小时前
leetcode 78子集
数据结构·算法·leetcode
喜欢吃燃面16 小时前
深入 C++ STL:从 unordered_set与unordered_map到底层哈希表的原理与实现
数据结构·c++·散列表
en.en..17 小时前
Linux fork() 工作原理
数据结构·算法
不会就选b18 小时前
数据结构之树&&二叉树(二)
数据结构·算法
小刘在重生~21 小时前
Java 集合|Collection、List、ArrayList、LinkedList、泛型、Collections 工具类
java·数据结构·list
我不会起名字32221 小时前
一天一道算法题(29):单调栈
java·数据结构·python·算法·leetcode·golang·单调栈
苦瓜小生21 小时前
【前端】【力扣与手撕】十天带你刷完前端算法与手撕,全是最简单好记的最优解法!day4
前端·数据结构·算法·leetcode·面试
少司府1 天前
C++进阶:智能指针
开发语言·数据结构·c++·b树·算法·c·智能指针