package csu.sort;
/**
* 堆排序
* 堆的定义:堆是一个完全,或近似完全的二叉树,堆顶元素的值大于左右孩子的值,左右孩子也需要满足这个条件;
* 按照堆的定义,堆可以是大顶堆(maxHeap),或小顶堆(minHeap);
* 一般用数组即可模拟二叉树,对于任意元素i,左孩子为2*i+1,右孩子为2*i+2;父节点为(i-1)/2
* 时间复杂度: 平均:O(nlogn);
* 空间复杂度: O(1);
*/
import java.util.Arrays;
import java.util.Random;
public class HeapSortAsc {
public void heapSort(int[] arr){
//先从最后一个非叶子节点向上调整,使得满足堆结构
for(int i=arr.length/2-1;i>=0;i--){
maxHeapAdjust(arr,i,arr.length-1);
}
//每次拿最后一个节点和第一个节点交换,然后调整堆;直到堆顶
for(int i=arr.length-1;i>0;i--){
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
maxHeapAdjust(arr,0,i);
}
}
/**
* 调整堆
* 把以i为跟节点的二叉树调整为堆
* 这个完全二叉树就像一个金字塔,塔顶的小元素沿着树结构,往下沉降
* 调整的结果是最大的元素在金字塔顶,然后把它从堆中删除(把它交换到堆尾,然后堆收缩一格);
* 堆排序快的原因就是根据二叉树的特点,一个节点要沉降到合适的位置,只需要logn步;
* 同时前期调整的结果(大小顺序)会被记录下来,从而加快后续的调整
* @param arr
* @param i
* @param len
*/
public void maxHeapAdjust(int[] arr,int i,int len){
int temp = arr[i];
int j = 2*i+1;//i的左孩子节点
while(j<len){
//从左右孩子中找出大的
//j+1为右孩子节点
if(j+1<len && arr[j+1]>arr[j]){
j++;
}
//找到合适的位置就不再找了
if(arr[j]<temp){
break;
}
//否则将较大的沿着树往上移动;
arr[i] = arr[j];
//i指向刚才的较大孩子
i=j;
//j指向新的左孩子节点
j= 2*i+1;
}
arr[i] = temp;
}
public static void main(String[] args) {
Random ran = new Random();
int[] arr = new int[20];
for(int i=0;i<20;i++){
arr[i]=ran.nextInt(100);
}
HeapSortAsc hsa = new HeapSortAsc();
hsa.heapSort(arr);
System.out.println(Arrays.toString(arr));
}
}
//输出结果:[1, 4, 14, 26, 27, 28, 28, 32, 35, 40, 41, 45, 48, 57, 58, 64, 68, 79, 88, 95]
排序之堆排序
最新推荐文章于 2023-12-18 17:02:49 发布