堆排序从入门到精通
吾学堆良久,阅百篇文章,然而未曾见一篇详尽其精髓,便属此文,以便他人学习,如有不足,还望大佬多多赐教。
啥是堆?
堆是一种数据结构,是一种完全二叉树
啥是完全二叉树?
尽量满足一个根节点有两个叶节点,(如果都满足了,就是满二叉树),如果满足不了,紧着最左边的使用,也就是说只有最后一层可以出现单节点的情况,而且是右侧不能出现单节点而左侧没有节点的情况。感觉说的不咋好,画个图来说明一下,
如上图所示,圆心的数字顺序即代表着添加叶子的顺序,从上到下,从左到右,依次进行,此时,这个就是一个完全二叉树。
如上图所示,新添加的节点8,在右侧,但是左侧有单节点和空孩子的节点,使用这个不符合完全二叉树
再看这一张,会发现所有的根节点都有左右孩子,不包含单节点的情况,所以这个叫做满二叉树。
小超:满二叉树一定是完全二叉树,但是完全二叉树不一定是满二叉树
咱们进入代码之前,先补习一下数学知识:
Question1:如何得到最后一个非叶子节点?
傻瓜式找规律:
先给张图:
总节点数(个) | 非叶子节点数(个) | 最后一个非叶子节点(编号) | 备注 |
---|---|---|---|
1 | 0 | null | 这个情况没用 |
2 | 0 | null | 从这个开始找规律 |
3 | 1 | 0 | 注意是编号!!! |
4 | 2 | 1 | |
5 | 2 | 1 | 有点意思 |
6 | 3 | 2 | |
7 | 3 | 2 | 靠,每两行一样啊 |
8 | 4 | 3 | |
9 | 4 | 3 | 是不是明白了? |
… | … | … | 还想不明白?无语了 |
arr.lengh | arr.lengh / 2 | (arr.lenght / 2) - 1 | 总节点数就是数组的长度 |
Question2:如何得到倒数第二个非叶子节点?
现在有个疑问,倒数第二个是从下往上找还是从左往右找?
因为从构建堆开始,我们是从上到下,从左到右进行的,所以倒数的找就是从右往左,从下到上,如上图所示。倒数的非叶子节点就是:6、5、4、3、2、1、0,具有极强的规律性
用代码表示就是(arr.lenght / 2) - 1 -1
相信找出倒数第三个非叶子节点也能明白了吧?那就再减1呗
该进入正题了,别急,再了解两个概念
大顶堆
每个非叶子节点的值都大于等于其左右孩子的数值
小顶堆
还用我解释?哼
堆排序
思想:
将数组构建成一个大顶堆(别抬杠,小顶堆也行),然后把根节点的元素和最后一个元素进行调换,此时末尾就是最大值,然后将剩余n-1个元素重新构建成一个堆,同上执行,得到第二个大的,如此反复,就实现排序了
代码:
import java.util.Arrays;
public class HeapSort {
public static void main(String[] args) {
int []arr = {
9,8,7,6,5,4,3,2,1};
sort(arr);
System.out.println(Arrays.toString(arr));
}
public static void sort(int[] arr