>>堆排序
堆排序是插入排序的一种,且利用了数据结构中的完全二叉树。
关于堆排序的实际流程,和什么是完全二叉树可以从这篇博客中了解:《堆排序就这么简单》。
堆排序的思路: 给定一个数组,将数组排成这样一个完全二叉树:每个顶点大于子节点的叫大顶堆,每个顶点小于子节点的叫小顶堆,大顶堆是升序,小顶堆的降序。然后将第一个节点所得到的最值,与最后一个节点交换,并立即维护这个完全二叉树,循环直到只剩一个节点。
平均时间复杂度: O(n log n)
最好情况: O(n log n)
最坏情况: O(n log n)
空间复杂度: O(1)
稳定性: 不稳定
: ) 堆排序代码
代码如下:
public static void heapSort(int[] value,int length){
//构建初始完全二叉树,从最后一个拥有子节点的节点开始
for(int j=(length/2-1);j>=0;j--){
buildHeapTree(value,j,length);
}
//这里不需要遍历到最后,因为当第二个数都已经排好序,那么第一个也就排好序了。
for(int i=length-1;i>0;i--){
//获得第一个值,这个值是最大值,放到最后
swap(value,0,i);
//获得值之后,保持二叉树是一个大顶堆
//从0开始维护,因为刚刚交换了它
//并且这里只需要维护到当前堆的大小,而不是整个数组的大小
//恰好,由于数组是0开始,这时的i就刚好等于排除最后一个数后堆的大小
buildHeapTree(value,0,i);
}
}
/*
* n :是当前待排顶点
* len : 是为了用于判断下标是否越界,所以传入的是待排二叉树大小
* */
private static void buildHeapTree(int[] value,int n,int len){
//获得左子节点
int left=n*2+1;
//获得右子节点
int right=left+1;
//将当前节点与子节点中最大且大于当前节点的值交换
//默认当前节点最大
int max=n;
//比较左节点
if(left<len&&value[left]>value[max]){
max=left;
}
//比较右节点
if(right<len&&value[right]>value[max]){
max=right;
}
if(max!=n){
swap(value,max,n);
//这一步非常重要,是构建和维护完全二叉树的关键
//因为将子节点中的最大值给了n,所以要确保被交换的子节点max(max是left,或者right)依然最大顶点
buildHeapTree(value,max,len);
}
}
private static void swap(int[] value,int i,int j){
int temp=value[i];
value[i]=value[j];
value[j]=temp;
}
代码量其实并不多,如果将注释去掉也就20来行。
代码里写了很多注释,就不再去解释代码了。
我想强调的是buildHeapTree()函数中 递归调用那一段buildHeapTree(value,max,len);
这段代码非常关键,是构建和维护完全二叉树最核心的句子。
我写的注释是:因为将子节点中的最大值给了n,所以要确保被交换的子节点max(max是left,或者right)依然是最大顶点。
: ) 运行结果
我利用快速排序做了比较,以测试排序是否正确,懒嘛,程序员的优点 ?,也作为一次复习。
快速排序代码如下:
/*
* 快速排序,用来检查堆排序是否正确
* */
public static void quikSort(int[] value,int start,int end){
if(start<end){
int i=start-1;
int j=start;
int X=value[end];
while(j<=end){
if(value[j]<=X){
i++;
swap(value,i,j);
}
j++;
}
quikSort(value,start,i-1);
quikSort(value,i+1,end);
}
}
: ) 总结
最初,堆排序对我来说相当的陌生,在搜查了资料后发现给出的代码根本啃不动,因此又去搜索了很多资料,思考了每一行代码,才终于弄清楚。上面的代码和我搜索到的大多数版本的代码不同,也许是我想的不够多,但是我还是将那些我觉得没有必要的代码删除掉了。精简后的代码是不是看着很舒服(如下)?
public static void heapSort(int[] value,int length){
for(int j=(length/2-1);j>=0;j--){
buildHeapTree(value,j,length);
}
for(int i=length-1;i>0;i--){
swap(value,0,i);
buildHeapTree(value,0,i);
}
}
private static void buildHeapTree(int[] value,int n,int len){
int left=n*2+1;
int right=left+1;
int max=n;
if(left<len&&value[left]>value[max]){
max=left;
}
if(right<len&&value[right]>value[max]){
max=right;
}
if(max!=n){
swap(value,max,n);
buildHeapTree(value,max,len);
}
}
private static void swap(int[] value,int i,int j){
int temp=value[i];
value[i]=value[j];
value[j]=temp;
}