基于堆的数据结构,形成了一种堆的排序算法,叫做堆排序。堆排序总的运行时间是。
这个算法的主要问题在于使用了一个附加的数组,存储需求增加了一倍,因此这里采用一种回避的算法:在每次deletemin后堆缩小1,位于堆中的最后的单元可以用来存放刚刚删除的元素。
算法的主要逻辑思路:
1、创建堆数据结构;
2、删除位于根最小值(或者最大值);
3、重新构造堆的结构;
4、重复2和3的操作,直到堆中元素删除完成。
下面看代码实现:
package structures.arithmetic;
/**
* 堆排序算法(寻找堆中最大值)
*/
public class BinarySort {
/**
*
* @param i 代表堆中父节点的位置
* @return 返回的是父节点中左子树的位置
*/
private static int leftChild(int i){
return 2 * i +1;
}
/**
* 找出i位置的节点的值应该存放的位置
* @param a 数组
* @param i 堆中需要排序的数据的位置
* @param n 堆的长度
* @param <AnyType>
*/
private static <AnyType extends Comparable<? super AnyType>> void percDown(AnyType[] a, int i, int n){
int child = 0;
AnyType tmp;
for(tmp = a[i]; leftChild(i)<n; i=child){
child = leftChild(i);
//寻找出i位置2个子节点中比较大的值得位置
if(child!=n-1&&a[child].compareTo(a[child+1])<0){
child++;
}
if(tmp.compareTo(a[child])<0){
a[i] = a[child];
}else{
break;
}
}
a[i] = tmp;
}
public static <AnyType extends Comparable< ? super AnyType>> void heapSort(AnyType[] a){
//将数组在二叉堆中排序
for(int i=a.length/2-1; i>=0; i--){
//这里取数组的长度的二分之一是因为后面的数据全部当做了子节点,不用构建二叉堆数据位置
percDown(a, i, a.length);
}
for(int i=a.length-1;i>0;i--){
//取出最大值,并放在数组的后面
swapReferences(a,0,i);
//重新构建二叉堆
percDown(a, 0, i);
}
}
/**
* 将数组中元素的位置交换
* @param a 数组
* @param i 要交换的元素在数组中的位置
* @param i1 要交换的元素在数组中的位置
*/
private static <AnyType extends Comparable<? super AnyType>> void swapReferences(AnyType[] a, int i, int i1) {
AnyType tmp = a[i];
a[i] = a[i1];
a[i1] = tmp;
}
}