-
堆排序 : 核心就是不断查询最大的元素 然后放到数组尾部即可
- 把数组堆化(大顶堆) 此时根节点就是最大的元素
- 把根节点值和数组最后一个元素进行替换 此时最大值就在末尾(之后进行替换时需要倒叙挨个往前替换)
- 对于替换后的堆 已经不满足大顶堆的定义 对其再次堆化 (注意 : 这里堆化时不包含已经替换到数组末尾的元素)
- 堆化完成后 根节点是最大元素 然后循环执行上面的步骤 直到最后一个元素
-
看如下例子 目前是一个已经堆化数组
-
替换首尾元素
-
由于此时已经不满足堆的定义 再次进行堆化
-
堆化后 进行元素替换
-
堆化
-
依次执行如上步骤 最终结果如下
-
将其放到数组后如下 注意 下标为0的位置为空 更节从下标为1的3开始 发现排序完成
2. 数组图示
3. 代码实现
import java.util.Arrays;
public class HeapSort {
public static void main(String[] args) {
int[] array = {8,6,5,9,2,10,3,1,15,22,22};
int[] sort = sort(array);
System.out.println(Arrays.toString(sort));
}
/**
* 排序方法 : 注意这里的核心是吧最大的元素放到数组最后面(就是一个在不断查询最大值的操作)
* 1.把堆化后的数组 根节点元素(最大的)和数组最后一个元素替换 此时堆顶元素不是最大值不满足大顶堆
* 2.需要重新进行堆化 有点类似于删除顶元素的操作
* 3.如此循环一下 就把最大的元素都依次放到了数组进行倒叙遍历的位置上
* 4.完成排序
* @param array
*/
public static int[] sort(int[] array){
int[] heapArray = array2Heap(array);//堆化数组
int n = heapArray.length - 1;
while (n > 0) {//当n<0时 说明数组已经遍历结束 即已经排序完成
//把堆顶元素和数组最后元素替换 没替换一次 进行n--操作 下一次就替换倒数第二个
// 以此类推 当最后一个元素替换完成后 则排序完成
swap(heapArray,1,n--);
//交换后需要进行一次堆化操作
//注意堆化的最后一个元素也要进行--操作 因为此时最大的元素已经在最后面 所以无需在进行操作
bigHeapDate2high(heapArray,1,n);
}
//由于之前堆化时 做了一个从1开始索引元素 现在 排序完成 在复制为从0开始
System.arraycopy(heapArray,1,array,0,array.length);
return array;
}
/**
* 把数组堆化方法 这里使用大顶堆
* @param array 堆化数组
*/
public static int[] array2Heap(int[] array) {
//把原数组复制到一个新数组 令其元素从1开始
int[] copy = new int[array.length + 1];
System.arraycopy(array,0,copy,1,array.length);
int endIndex = copy.length - 1;//数组最后一个元素下标
//endIndex / 2 : 获取到最后一个节点的父节点下标
for (int i = endIndex / 2; i > 0; i--) {
bigHeapDate2high(copy, i, endIndex);
}
return copy;
}
/**
* 堆化为大顶堆
*
* @param data
* @param beginIndex 替换后的节点索引
* @param endIndex 结束位置索引
*/
public static void bigHeapDate2high(int[] data, int beginIndex, int endIndex) {
int left,right;
while (true) {//当前元素下标小于总元素个数时 进行替换操作
//判断节点和左子树大小且左子树值要小于右子树值时 大于就替换位置
if ((left = 2 * beginIndex) <= endIndex
&& data[beginIndex] < data[left]
&& ((right = 2 * beginIndex + 1) > endIndex ? true : data[left] > data[right])) {
swap(data, beginIndex, left);
beginIndex = left;
} else if ((right = 2 * beginIndex + 1) <= endIndex && data[beginIndex] < data[right]) {
//否则判断节点和右子树大小 大于就替换位置
swap(data, beginIndex, right);
beginIndex = right;
}else {
break;
}
}
}
//替换元素位置
public static void swap(int[] array, int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}