堆排序
堆排序的基本思想:
- 将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。
堆排序的基本思路:
- a.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
- b.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
- c.重新调整结构,使其满足堆定义,
- d.然后继续交换堆顶元素与当前末尾元素,反复执行b和c步骤,直到整个序列有序。
代码实现
import java.util.Arrays;
//堆排序 算法实现Demo on 2018年8月31号
public class HeapSort {
public static void main(String[] args) {
// 待排序数据
int[] arr = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
// 堆排序
sort(arr);
// 打印输出
System.out.println(Arrays.toString(arr));
}
private static void sort(int[] arr) {
// 1、构建大顶堆
for (int i = arr.length / 2 - 1; i >= 0; i--) {
// 从arr.length / 2 - 1:(最后一个非叶子节点 )开始从左到右,从下至上调整结构
adjustHeap(arr, i, arr.length);
}
// 2、正式开始排序,堆顶元素与数组末尾元素交换+从根结点开始调整堆结构
for (int j = arr.length - 1; j > 0; j--) {
swap(arr, 0, j);
adjustHeap(arr, 0, j);
}
}
/* 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
* 每层开始都是从走左结点开始
* 同一层时:从左结点至右结点,从子节点结点至根结点进行调整,然后查看左右结点是否存在非叶节点
*
*/
private 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开始 !!!
*这是因为发生过交换,,不能保证左右子节点作为非叶节点(k=k*2+1)时,取得最大值,所以得再进行调整堆结构,(构建大顶堆不会出现(从最后一个结点开始),正式开始排序时(从根结点开始),才会发生);*/
if( k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子节点( k+1<length:并且右子节点存在),k指向右子节点
k++;
}
if(arr[k]>temp){ //如果 子节点 大于父节点,将子节点值赋给父节点(不用进行交换)
arr[i]=arr[k];
i=k; //将子节点位标识出来
}else{
break;
}
}
arr[i]=temp; /*两种可能:1、沒有发生元素交换,即根元素就是最大值,则将原值赋给根元素(位置和属性没有发生任何改变)
* 2、存在左右结点值比根元素大,此时i已变为该结点的位置H,则将根元素值赋给比根元素大的结点(位置和属性都将改变)
*/
}
private static void swap(int[] arr, int i, int j) {
int temp=arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}