堆是一种除了底层节点外的完全填满的二叉树,底层可以不完全,左到右填充。堆在实现优先队列的时候很有用。堆又分为大根堆和小根堆。大根堆的父节点的值大于等于两个子节点的值。小根堆的父节点的值小于等于两个子节点的值。
堆排序的思想是:每次从堆中取出最小(大)值,将取出的元素按顺序排到数组中,这样所有的元素就是从小到大(从大到小)排列在数组中。我们可以把删除最小值得到的元素重新排在一个数组中,或者排在该数组的末尾,减少空间。对堆的操作不是很难,插入就是将元素进行上滤。删除最小值相当于把树根置为空穴,将这个空穴下滤,下滤通过,两个子节点中最小的元素和空穴进行交换位置,下滤到最下面一层时,将数组末尾的元素放到空穴,保证每层是从左到右插入数据,最后将该元素上滤,保证父元素比两个子元素大。
代码
package com.creat.sort;
import org.junit.Test;
/**
* Created by whz on 2017/8/23.
*/
public class HeapSort {
@Test
public void test(){
Integer[] array = new Integer[]{10,54,55,47,50,20,41,33,40,28,70};
Integer[] newArray = new Integer[array.length+1];
buildHeap(array,newArray);
sort(newArray,array);
for(int i = 0; i < array.length; i++){
System.out.print(array[i]+" ");
}
System.out.println();
}
//排序
public static <T extends Comparable<? super T>> void sort(T[] array,T[] newArray){
int length = array.length;
for(int i = 0; i < newArray.length; i++){
newArray[i] = deleteMin(array,newArray.length -i );
}
}
//构建小根堆
public static <T extends Comparable<? super T>> void buildHeap(T[] array,T[] newArray){
newArray[0] = null;
for(int i = 1; i <= array.length; i++){
insert(newArray,array[i-1],i);
}
}
//删除最小值
private static <T extends Comparable<? super T>> T deleteMin(T[] array,int size){
T result = array[1];
array[1] = null;
int index = 1;
while(index*2 < array.length-1 && array[index*2] != null ){
if(array[index*2+1] == null || array[index*2].compareTo(array[index*2+1]) < 0){
array[index] = array[index*2];
index *= 2;
}else{
array[index] = array[index*2+1];
index = index*2+1;
}
}
insert(array,array[size],index);
array[size] = null;
return result;
}
//插入
private static <T extends Comparable<? super T>> void insert(T[] array,T value,int place){
if(((double)place)/2%1 == 0){
int index = place;
if(index!=1 && array[index/2].compareTo(value) > 0 ){
array[index] = array[index/2];
insert(array,value,index/2);
}else {
array[index] = value;
}
}else {
int index = place;
if (index!=1 && array[(index-1)/2].compareTo(value) > 0 ){
array[index] = array[(index-1)/2];
insert(array,value,(index-1)/2);
}else {
array[index] = value;
}
}
}
}
堆排序的时间复杂度,最坏,平均,最好都为O(Nlog2N)。