堆的定义:
- 大顶堆:arr[i]>=arr[2i+1]&&arr[i]>=arr[2i+2]
- 小顶堆:arr[i]<=arr[2i+1]&&arr[i]<=arr[2i+2]
堆排序的思想:
- 对于给定的N个记录,初始化时把这些记录看做一颗顺序存储的二叉树,然后将其调整为一个大顶堆,然后将堆的最后一个元素与堆顶元素(二叉树的根节点)进行交换,交换后堆的最后一个元素即为最大记录;
- 接着将前(n-1)个元素重新调整为一个大顶堆,再将堆顶元素与当前堆的最后一个元素进行交换后得到次打记录,重复该过程 直到调整堆中只剩一个元素为止,该元素为最小记录,此时可得到一个有序序列。
算法步骤:
- 构建一个堆,根据需要调整为大/小顶堆,
- 将堆顶元素与末尾元素交换,将最大元素沉到末尾
- 重新调整1,2,直到序列有序
堆调整的过程:
- 从第一个非叶子节点开始,判断其是否大于左右孩子,如果小于则交换
- 依此向前逐个遍历节点,每次交换节点之后需要判断其子节点是否收到影响,如果受到影响则交换
堆排序代码:
public class HeapSort {
private static void heapSort(int[] arr, int count) {
//1.构建大顶堆
for(int i=arr.length/2-1;i>=0;i--){
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(arr,i,arr.length);
}
//2.调整堆结构+交换堆顶元素与末尾元素
for(int j=arr.length-1;j>0;j--){
swap(arr,0,j);//将堆顶元素与末尾元素进行交换
adjustHeap(arr,0,j);//重新对堆进行调整
}
}
/**
* 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
* @param arr
* @param i
* @param length
*/
public static void adjustHeap(int []arr,int i,int length){
int temp = arr[i];//先取出当前元素i
for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始
if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
k++;
}
if(arr[k] >temp){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
arr[i] = arr[k];
i = k;
}
}
arr[i] = temp;//将temp值放到最终的位置
}
//交换
public static void swap(int[] arr, int n, int m) {
int temp = arr[n];
arr[n] = arr[m];
arr[m] = temp;
}
public static void main(String [] args){
int [] array={38,65,97,76,13,27,49,73,28,45};
//堆排序
heapSort(array, array.length);
for(int i=0;i<array.length;i++){
System.out.println(array[i]+" ");
}
}
}
参考:《java面试宝典=》