网上很多堆排序都有问题,我写的这个我测试是没问题的,如果有问题请指出!
算法思想
堆排序是利用堆这个数据结构,堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆这个等我写完排序再看。
算法步骤
1.将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
2.将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
代码实现
class HeapSort{
public static void main(String[] args) {
int []a= {1,3,2,4,5,4,8,6,-1,10};
int n=a.length;
//建堆,下标一定要n/2-1开始,算法导论数组是从1开始的,网上很多有问题。
for (int i=n/2-1;i>=0;i--){
maxHeap(a,n,i);
}
//交换最大值到最后的位置
for (int j=n-1;j>0;j--){//j到1的时候就只需要交换0,1,不会再调整堆了
int t=a[0];
a[0]=a[j];
a[j]=t;
maxHeap(a,j,0);//其他地方已经满足大顶堆性质,只需要从根元素再调整一次,长度变成j
}
for (int i=0;i<n;i++) {
System.out.print(a[i]+",");
}
}
public static void maxHeap(int[]a,int n,int index){
for (int k=2*index+1;k<n;k=2*index+1){
int temp=a[index];
//找到最大的子节点
if (k+1<n&&a[k+1]>a[k])k++;
//如果子节点大则交换父子节点
if (a[k]>temp){
a[index]=a[k];
a[k]=temp;
//这里是重点,如果交换,则要看会不会对子树有什么影响,上面for循环体内结束是k=2*index+1,
// 如果没到子节点,得继续检查子树
index=k;
}
else break;//如果没换则直接终止
}
}
}
算法分析
外层循环规模为n,manHeap里面的循环规模取2为底n的对数,总的复杂度是O(nlog(n)),补充一点,推排序一般用不到,但是构建堆的过程经常用来进行部分排序,降低总体时间复杂度。