堆
堆中某个节点的值总是大于等于(最大堆)或小于等于其子节点(最小堆)的值,并且堆是一颗完全二叉树。
以下我们以最大堆来讨论堆排序。
堆排序
既然堆顶永远是最大的,我们就可以把堆顶的元素给拎出来,放在有序队列中,然后对于剩下的元素再次构建成堆,再取堆顶的元素排到有序队列中,以此反复循环。直到堆中只有一个元素那么排序完成。
以一下数组为例
{50,11,2,4,5,48,1}
50
/ \
48 11
/ \ / \
4 5 2 1
将50取出,与末尾元素交换位置
{1,11,2,4,5,48, 50}
再将剩余的数构建成一个新的堆
48
/ \
11 5
/ \ / \
4 2 1
将48取出,与末尾元素交换位置
{1,11,2,4,5, 48,50}
再将剩余的数构建成一个新的堆
11
/ \
5 4
/ \
4 2
将11取出,与末尾元素交换位置
{1,2,4,5, 11,48,50}
再将剩余的数构建成一个新的堆
以此类推完成排序
代码实现
package sort;
import java.util.Arrays;
public class Heap {
private static void sort(int[] arr) {
int length=arr.length;
int temp;
//构建堆
buildHeap(arr,length);
for(int i=length-1;i>=0;i--){ //需要执行的次数为 length次
//将堆顶元素与数组末尾元素交换
temp=arr[i];
arr[i]=arr[0];
arr[0]=temp;
//数组长度-1 隐藏堆尾元素
length--;
//将堆顶元素下沉 目的是将最大的元素浮到堆顶来
sink(arr,0,length);
}
}
/**
* 构建堆
* @param arr
* @param length 数组范围
*/
public static void buildHeap(int[]arr,int length){
for(int i=length/2;i>=0;i--){
sink(arr,i,length);
}
}
/**
* 下沉调整
* @param arr
* @param index 调整位置
* @param length 数组范围
*/
private static void sink(int[] arr, int index, int length) {
int leftChild=index*2+1;//左节点
int rightChild=index*2+2;//右节点
int present=index; //要调整下移的节点
//如果左边比节点大,则往左边下沉
if(leftChild<length && arr[leftChild]>arr[present]){
present=leftChild;
}
//如果右边比节点大,则往右边下沉
if(rightChild<length && arr[rightChild]>arr[present]){
present=rightChild;
}
//如不相同则发现了大于节点的数,需要交换位置
if(present!=index){
int temp = arr[present];
arr[present]=arr[index];
arr[index]=temp;
//继续下沉
sink(arr,present,length);
}
}
public static void main(String[] args) {
int [] arr= {8,2,5,9,7,3};
sort(arr);
System.out.println(Arrays.toString(arr));
}
}
堆排序除了下沉,还有上浮,也就是把堆顶的元素与首个元素的交换。以此方法进行排序
此文章创于本人学习时的记录,如有错误或更优解还请指出