二叉树的特性
* 左子树下标 = 父节点下标 * 2 + 1
* 右子树下标 = 父节点下标 * 2 + 2
代码如下:
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 堆排序算法
* @author yinglala
*/
public class Heap {
/**
* 基本思想:将待排序的序列构造成一个大顶堆,此时整个序列的最大值就是堆顶的根节点
* 将它移走(其实就是将其与对数组的末尾元素交换,此时末尾元素就是最大值)
* 然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值。
* 如此反复执行 就可以得到一个有序队列了
*
* 利用二叉树的特性
* 左子树下标 = 父节点 * 2 + 1
* 右子树下标 = 父节点 * 2 + 2
* @param list 待排列的集合
*/
public static void heapSort(List<Integer> list){
//把list构建成一个大顶堆
//list.size()/2-1 为有子孩子的节点的最大下标
for(int i = list.size()/2-1; i >= 0 ; i--){
heapAdjust(list,i,list.size());
}
for(int i = list.size()-1 ; i >= 0 ; i--){
//将堆顶记录和当前未经排序的子序列的最后一个记录交换
swap(list,0, i);
//将list进行排序
heapAdjust(list,0,i);
}
}
/**
* 交换根节点 和 最后一个节点的值
* @param list
* @param root
* @param last
*/
private static void swap(List<Integer> list, int root, int last) {
int temp = list.get(last);
list.set(last,list.get(root));
list.set(root,temp);
}
/**
* 调整堆使得以i为顶的堆为大顶堆
* @param list
* @param i
* @param size
*/
private static void heapAdjust(List<Integer> list, int i, int size) {
int temp = list.get(i);
//左子树下标 = 2i+1 右子树下标为2i+1+1
for(int j = 2*i + 1; j < size; j = 2*j + 1){
if(j+1 < size && list.get(j) < list.get(j+1))
//j为关键字中较大的记录的下标
++j;
if(temp >= list.get(j))
//由于大顶堆的构造过程是自下而上进行的
//父节点>=左右孩子节点,则父节点一定大于孩子节点的子孙节点
//但若父节点<左(右)节点,不能保证父节点是否小于孙子节点,所以要继续去判断
break;
list.set(i,list.get(j));
i = j;
}
list.set(i,temp);
}
@Test
public void heapSockTest(){
List<Integer> list = new ArrayList<>(9);
list.addAll(Arrays.asList(50,10,90,30,70,40,80,60,20));
heapSort(list);
list.forEach(i -> System.out.print(i + " "));
}
}