堆排序
1.堆的基本介绍
1)堆排序是利用堆的这种数据结构设计的排序算法,堆排序是一种选择排序,最好最坏时间复杂度为O(nlogn),它是不稳定的排序。
2)堆是具有以下性质的完全二叉树:每个节点的值都大于或等于其左右孩子结点的值,称为大顶堆,注意:没要求左右孩子之间的关系。
3)每个结点的值都小于或等于左右孩子结点的值为小顶堆
4)大顶堆
5)小顶堆
2.堆排序的思想
1)将待排序列构成一个大顶堆,此时整个序列的最大值就是堆顶的根节点;
2)将其与末尾元素进行交换,此时末尾元素为最大值;
3)然后将最大元素取出,剩下的n-1个元素重新构造成一个大顶堆,如此反复执行,便能得到一个有序序列。
3.构建大顶堆步骤
1)假设给定无序序列结构如下
2)此时我们从最后一个非叶子节点开始(叶子节点不用调整,第一个非叶子节点:arr.length/2-1,也就是下面的6结点),从左至右,从下至上调整。让6与自己的左右子节点进行比较,与大的交换,如下图
3)找到第二个非叶子节点4,由于【4,9,8】中9最大,4和9交换
4)这时,交换导致左子树【4,5,6】结构混乱,继续调整,将4和6交换
5)此时完成,
代码:
package com.sratct.tree;
import java.util.Arrays;
public class HeapSort {
public static void main(String[] args) {
int [] arr = {14,52,31,61,41,25,32,16,62};
headSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void headSort(int[] arr) {
int temp =0;
// 构建大顶堆
for (int i = arr.length/2-1; i>=0; i--) {
adjustHeap(arr, i, arr.length);
}
// 将堆顶元素和末尾元素交换,再重新构建
for (int j=arr.length-1;j>0;j--) {
// 交换元素
temp = arr[0];
arr[0] =arr[j];
arr[j] = temp;
adjustHeap(arr,0,j);
}
}
/* *
* 以i对应的非叶子节点,将其调整为大顶堆
* @param arr 待数组
* @param i // 表示非叶子节点在数组中的索引
* @param length 表示对多少个元素进行调整,length逐渐减少*/
public static void adjustHeap(int[] arr, int i, int length) {
int temp = arr[i]; // 需要调整的值
// k的初始值为i结点的左子结点
for (int k = i*2+1; k<length; k=k*2+1) {
if (k+1<length && arr[k] < arr[k+1]) {
k++;
}
if (temp < arr[k]) {
arr[i] = arr[k]; // 将较大值赋给当前结点
i = k;
} else {
break;
}
}
// 当for循环结束后,已将i为父节点的树的最大值,放在了最顶(局部)
arr[i] = temp; // 结束后将temp放到调整后的位置
}
}