一、堆是什么
- 堆是一种数据结构,一般用一个数组表示,比如int[]。
- 堆与数组的区别是: 堆的下标表示是由三个组成,分别是 n,2n+1,2n+2 其中
n称为父节点,2n+1称为左子节点,2n+2称为右子节点。 - 由于堆结构,把数据规划成一个图,类似树形结构 ,跟完全二叉树类似,所以,一个堆结构中,也会有根节点,非叶子节点,叶子节点。根节点指的是下标为0的数据,非叶子节点指的是既不是根节点,又含有子节点的数据。
二、最大顶堆和最小顶堆
每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。如下图:
三、堆排序的思想
堆排序是基于堆这种数据结构的排序,一般基于最大堆进行排序,默认堆的根节点是最大值,所以获取最大值
的时间复杂度是O(1),而其他值是无序的,但是父节点一定大于子节点。堆排序的思想是,每次把最大值跟数
组里最后一个值交换,然后把剩下的数据当做一个新的堆,然后重新调整新堆为最大堆,然后再把最大值和倒
数第二位交换位置,依次循环执行。由于调整堆的方法是一样的,只需循环调用用调整的方法,传入不同的数
组长度值即可。详细请看以下的代码过程。
四、堆排序的java实现和详解
public static void main(String[] args) {
int[] arr=new int[]{1,3,2,9,10,7,8,1,63,18,21,1,0,-1,99,100};
sort(arr,false); //正序 ,正序构建最大顶堆
// sort(arr,true); //反序 , 反序构建最小顶堆
System.out.println(Arrays.toString(arr));
}
/**
* 堆排序 主要分两步:
* 第一步:构建最大顶堆。
* 调整的顺序:自下而上,自左向右调整
* 方法:从最大的非叶子的节点,开始调整
* code:最大的非叶子的节点下标是 floor((n-1)/2)
*
* 第二步:排序
*
* 交换最大值到数组最后
* 调整剩余的数组成的堆。
*
*/
public static void sort(int[] arr,boolean reverse){
for (int i = arr.length/2-1; i >=0; i--) { // 构建最大/小顶堆
adjustHeap(arr,i,arr.length-1,reverse);
}
for (int i = arr.length-1; i >=0; i--) {
swap(arr,0,i); //交换根节点和数组最后一个数
adjustHeap(arr,0,i-1,reverse); //从根节点开始重新调整
}
}
/**
* 调整方法:
* @param arr
* @param current 当前节点
* @param length
*/
public static void adjustHeap(int[] arr,int current,int length,boolean reverse){
int li = (current << 1) + 1; // 左子节点索引 index * 2 +1
int ri = li + 1; // 右子节点索引 左子节点+1
int temp = li; // 子节点最大值的索引
if (li > length) return; // 子节点索引超出计算范围,直接返回。
if(reverse){
if (ri<=length && arr[ri] < arr[li]) {// 先判断左右子节点,哪个较小。
temp = ri; //保存最小值的下标
}
if (arr[temp] < arr[current]) { //比较当前节点和子节点的最小值
swap(arr,temp,current); // 交换位置
adjustHeap(arr,temp,length,true); // 如果原有最小值还有子节点,向下递归,从下往上调整
}
}else {
if (ri<=length && arr[ri] > arr[li]) {// 先判断左右子节点,哪个较大。
temp = ri; //保存最大值的下标
}
if (arr[temp] > arr[current]) { //比较当前节点和子节点的最大值,哪个大,交换位置
swap(arr,temp,current); // 交换位置
adjustHeap(arr,temp,length,false); // 如果原有最大值还有子节点,向下递归,从下往上调整
}
}
}
/**
* 交换位置
* @param arr
* @param max
* @param current
*/
public static void swap(int[] arr,int max,int current){
int temp=arr[max];
arr[max]=arr[current];
arr[current]=temp;
}