马不停蹄,堆上昨晚 ---------堆的代码
public class Test {
public static void main(String[] args) {
Integer[] arr = {17, 9, 25, 21, 19, 12, 18, 23, 16, 15};
Heap.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
public static calss Heap{
//创建堆
private static void createHeap(Comparable[] arr, Comparable[] heap){
System.arraycopy(arr, 0, heap, 0, arr.length);//将乱序数组拷贝到堆中
//从最后一个下标开始倒着往第一个父节点按堆的规则排序,
//父节点与两个子节点间只有两个数要做换位,因此只需要遍历长度的一半即可
for(int i = heap.length / 2; i >= 0; i--){
heapify(heap, i, heap.length - 1);
}
}
//大顶堆的排序规则,两个子节点比父节点小 index当前要排序的节点下标, n未排序的范围
private static void heapify(Comparable[] heap, int index, int n){
// 左子节点的小标小于或等于未排序范围的话,说明有左子树
while((2 * index + 1) <= n ){
//标记左子树或是右子树哪个更大
int max;
//如果右子树小于未排序范围的话,说明有右子树
if((2 * index + 2) <= n){
//对比左子树与右子树元素的大小
if(less(heap, 2 * index + 1, 2 * index + 2)) {
max = 2 * index + 2;//比较结果右子树大,标记为大的下标
}else{
max = 2 * index + 1;//比较结果左子树大,标记为大的下标
};
}else{
max = 2 * index + 1;//如果没有右子树,标记左子树为大的下标
}
if(!less(heap, index, max)){//当前节点大于最大小标,说明没有子节点则跳出循环
break;
}
exch(heap, index, max);//将当前节点元素与标为最大下标元素换位
index = max;//换位之后当前节点就是最大下标
}
}
public static void sort(Comparable[] arr){
Comparable[] heap = new Comparable[arr.length];//创建堆数组
createHeap(arr, heap);//将数组放入堆中,生成一个按堆原则排列的堆
int tail = heap.length - 1;//最后一个下标为堆的长度减一
while(tail != 0){//堆的最后一个元素不是第一个元素
exch(heap, 0, tail);//将大顶堆的最大元素放到最后一个下标处
tail --;//按堆的小标顺序倒着排序
heapify(heap, 0, tail);//按大顶堆规则再次将被打乱顺序的堆排序
}
System.arraycopy(heap, 0, arr, 0,arr.length);//将排好序的堆拷贝到数组上
}
private static boolean less(Comparable[] heap, int i, int j){
return heap[i].compareTo(heap[j]) < 0;
}
private static void exch(Comparable[] heap, int i, int j){
Comparable temp;
temp = heap[i];
heap[i] = heap[j];
heap[j] = temp;
}
}