一.堆的构造
堆的构造,最直观的想法就是另外再创建一个新数组,然后从左往右遍历原数组,每得到一个元素后,添加到新数组中,并通过上浮,对堆进行调整,最后新的数组就是一个堆。
上述的方式虽然很直观,也很简单,但是我们可以用更聪明一点的办法完成它。
①创建一个新数组把原数组0 ~ length-1的数据拷贝到新数组的1~ length处(舍弃掉索引0)
②再从新数组长度的一半处开始往1索引处扫描(从右往左),然后对扫描到的每一个元素做下沉调整即可。
为什么从一半处开始下沉:
因为堆的性质,大于一半的都是叶子结点,而叶子节点处于末端不需要再下沉,所以从堆的一半开始下沉即可以。
二.堆的排序
需求:排序后为从小到大的顺序,元素越大,其所处的索引就越大
对构造好的堆,我们只需要做类似于堆的删除操作,就可以完成排序。
- 将堆顶元素和堆中最后一个元素交换位置;(即最大的数放到索引最大的位置)
- 通过对新的堆顶元素下沉sink调整堆,把最大的元素放到堆顶使其有序(此时最后一个元素不参与堆的调整,因为最大的数据已经到了数组的末尾)
- 重复1~2步骤,直到堆中剩最后一个元素。
代码:
public class heapSort<T extends Comparable> {
//堆排序
public static void sort(Comparable[] source) {
Comparable[] heap = new Comparable[source.length + 1]; //因为0要被废弃掉
//构建堆
createHeap(source, heap);
//定义一个变量,记录未排序的 索引最大的元素
int N=heap.length-1; //记录最大索引N,第一轮是数组长度减一
//循环,交换根节点和未排序的索引最大处的元素
while(N!=1) {
swap(heap, 1, N);
//排除交换后最大元所在索引,也就是排除索引最大数
N--;
//对新的索引1处的元素到 N使用sink方法
sink(heap, 1, N);
}//把heap再传回source
System.arraycopy(heap,1,source,0,source.length);
}
//创建堆
private static void createHeap(Comparable[]source ,Comparable[]heap){
//把source的元素拷贝到heap中,heap中的元素就形成了堆(暂时无序)
System.arraycopy(source,0,heap,1,source.length);
//对堆的元素做下沉调整(从长度的一半处,往索引1处逐个使用下沉方法)
for(int i=(source.length)/2;i>0;i--){
sink(heap,i,heap.length-1); //heap是从1开始的,
}
}
private static boolean more(Comparable[] heap,int i,int j){ //比较
return (heap[i].compareTo(heap[j])>0);
}
private static void swap(Comparable[]heap,int i ,int j){ //交换
Comparable temp=heap[i];
heap[i]=heap[j];
heap[j]=temp;
}
private static void sink(Comparable[] heap, int target, int range) { //在0到range范围下沉
int max = 0;
while (2 * target <= range) { //循环条件:存在左子结点
if (2 * target + 1 <= range) { //如果有右子节点
//1. 找出当前结点的子节点中大的那个max
if (more(heap, target * 2, target * 2 + 1)) {
max = target * 2;
} else {
max = target * 2 + 1;
}
} else {
max = target * 2;
}
//2. 比较当前结点和max,若当前结点小则需要和max交换
if (more(heap, max, target)) {
swap(heap, max, target);
target = max; //更新当前结点target
} else {
break;
}
}
}
public static void main(String[] args) {
String[] arr = {"S", "O", "R", "T", "E", "X", "A", "M", "P", "L", "E"};
heapSort.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
测试结果:[A, E, E, L, M, O, P, R, S, T, X]