1.推排序需要满足的条件
- 完全二叉树 (除了最后一层结点都在最左边,其他层(1-h-1)结点都是最大个数,只能从左向右,从上到下添加结点)
- 父结点的值大于子结点的值(大顶堆)
- 父结点的值小于子结点的值(小顶堆)
2.怎么构建堆
1、每次找出子结点的最大值,和父结点做交换
2、从h-1往上进行heapify
3.怎么用代码表示堆
1、可以用一维数组表示堆,int[] arr = {}; 因为它是完全二叉树,并不会断开,假如根结点从0开始,
i=4,那么父结点就是(i-1)/ 2 向下取整,子节点就是2i+1和2i+2
4.流程
参考链接: 添加链接描述
1、首先用无序序列构造初始堆
- 先从最后一个非叶子结点开始,也就是h-1层,从叶子结点中找到最大值和根结点进行交换,然后接着对h-2层进行同样的处理,直到最后1层,如果由于交换,此时子根不满足大顶堆的性质的话,那么就再次进行调整。
2、然后将堆顶元素和末尾元素进行交换,接着继续调整堆(这里是从根结点开始调整),继续将堆顶元素和末尾元素交换,直到最后序列有序。
5.代码
参考链接:添加链接描述
/**
* @author: gethin
* @create: 2018-05-23 16:21
* @description: 常用排序算法
**/
public class Sort {
public static void main(String[] args) {
int[] nums = {16,7,3,20,17,8};
headSort(nums);
for (int num : nums) {
System.out.print(num + " ");
}
}
/**
* 堆排序
*/
public static void headSort(int[] list) {
//构造初始堆,从第一个非叶子节点开始调整,左右孩子节点中较大的交换到父节点中
for (int i = (list.length) / 2 - 1; i >= 0; i--) {
headAdjust(list, list.length, i);
}
//排序,将最大的节点放在堆尾,然后从根节点重新调整
for (int i = list.length - 1; i >= 1; i--) {
int temp = list[0];
list[0] = list[i];
list[i] = temp;
headAdjust(list, i, 0);
}
}
private static void headAdjust(int[] list, int len, int i) {
int k = i, temp = list[i], index = 2 * k + 1;
// < len是条件,index要有边界
while (index < len) {
if (index + 1 < len) {
if (list[index] < list[index + 1]) {
index = index + 1;
}
}
if (list[index] > temp) {
// 这里是为了调整后面的子结点
list[k] = list[index];
k = index;
index = 2 * k + 1;
} else {
break;
}
}
// 最后确定这个值在哪里
list[k] = temp;
}
}
时间复杂度为O(nlogn)