堆排序基本介绍
- 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最好、最坏、平均时间复杂度均为O(nlogn),它是不稳定排序。
- 堆是具有以下性质的完全二叉树:每个节点的值都大于等于其左右子节点的值,称为大顶堆,注意:没有要求最有子节点值得大小关系。
- 每个节点的值都小于等于左右子节点的值,称为小顶堆。
- 大顶堆的特点:arr[i ] >= arr[2i+1] && arr[i] >= arr[2i+2], i 对应第几个节点,i 从编号0开始。
- 小顶堆的特点: arr[i ] <= arr[2i+1] && arr[i] <= arr[2i+2], i 对应第几个节点,i 从编号0开始。
- 一般升序采用大顶堆,降序采用小顶堆。
堆排序基本思想
- 将待排序序列构造成一个大顶堆
- 此时,整个序列的最大值就是堆顶的根节点。
- 将其与数组末尾元素进行交换,此时末尾就为最大值。
- 然后将剩余 n-1 个元素重新构建成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列。
可以看到在构建大顶堆的过程中,元素的个数逐渐减少,最后得到一个有序序列了
一个数组中非叶子节点的个数 = arr.length / 2 – 1
代码案例
packagecom.xie.tree;
publicclassHeapSort{
publicstaticvoidmain(String[]args){
int[]arr=newint[8000000];
for(inti=0;i<8000000;i++){
arr[i]=(int)(Math.random()*800000000);
}
longstart=System.currentTimeMillis();
heapSort(arr);
longend=System.currentTimeMillis();
System.out.println("耗时:"+(end-start)+"ms");
/**
*800万数据
*堆排序!!
*耗时:2482ms
*/
}
publicstaticvoidheapSort(int[]arr){
inttemp=0;
System.out.println("堆排序!!");
//1.将无序序列构成一个堆,根据升序降序需求选择大顶堆或小顶堆
for(inti=arr.length/2-1;i>=0;i–){
adjustHeap(arr,i,arr.length);
}
//2.将堆顶元素与数组末尾元素交换,将最大元素"沉"到数组末端
//3.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。
for(intj=arr.length-1;j>0;j–){
//交换
temp=arr[j];
arr[j]=arr[0];
arr[0]=temp;
adjustHeap(arr,0,j);
}
}
/**
*将一个数组(二叉树),调整成一个大顶堆
*功能:完成将以i对应的非叶子节点的树调整成大顶堆
*
*@paramarr待调整的数组
*@parami表示非叶子节点在数组的索引
*@paramlength表示对多少个元素进行调整,length在逐渐减少
*/
publicstaticvoidadjustHeap(int[]arr,inti,intlength){
//先取出当前元素的值,保存在临时变量
inttemp=arr[i];
//k=2*i+1是i节点的左子节点
for(intk=2*i+1;k<length;k=k*2+1){
//当左子节点值小于右子节点值
if(k+1<length&&arr[k]<arr[k+1]){
k++;//k指向右子节点
}
//如果子节点值大于父节点值
if(arr[k]>temp){
//把较大的值赋给当前节点
arr[i]=arr[k];
//!!!i指向k继续循环比较
i=k;
}else{
break;
}
}
//当for循环结束后,我们已经将以i为父节点的树的最大值,放在了最顶。
//将temp值放到调整后的位置
arr[i]=temp;
}
}
原文地址:https://www.toutiao.com/i6935055440891986470/