堆排序
堆排序
先了解一些性质:1、complate binary tree,2、父节点的值大于其左、右孩子节点的值
堆排序是基于完全二叉树实现的,在将一个数组调整成一个堆的时候,关键之一的是确定最后一个非叶子节点的序号,这个序号为:n/2-1,n为数组的长度。但是为什么呢?
可以分两种情形考虑:
- 堆的最后一个非叶子节点若只有左孩子
- 堆的最后一个非叶子节点有左右两个孩子,完全二叉树不可能只有右孩子,而没有左孩子
完全二叉树的性质之一是:如果节点序号为i,在它的左孩子序号为:2i+1,右孩子序号为:2i+2。
package org.study.order;
import java.util.Arrays;
public class HeapSort {
public static void main(String[] args) {
int[] arr = {2, 6, 4, 11, 2, 6, 9, 7, 8, -1, 0};
sort(arr);
System.out.println(Arrays.toString(arr));
}
public static void sort(int[] arr) {
//先原地建最大堆
int heapSize = arr.length;
for (int i = (heapSize >> 1) - 1; i >= 0; i -- ) { //(heapSize >> 1) - 1:最后一个非叶子节点的索引
siftDown(arr, i, arr.length); //自下而上的下虑
}
while (heapSize > 1) {
swap(arr, 0, heapSize - 1); //0 堆顶部元素、heapSize-1 堆的尾部元素
heapSize --; //取出最大的元素
siftDown(arr, 0, heapSize); //恢复最大堆的性质
}
}
public static void siftDown(int[] arr, int parent, int length) {
//先保存即将下沉节点的值
int element = arr[parent];
int child = 2 * parent + 1; //先拿到左子节点,默认左子节点比较大
while (child < length) {
//存在右子节点,并且右子节点比较大
int rightChild = child + 1;
if (rightChild < length && arr[child] < arr[rightChild]) {
child = rightChild;
}
//如果比自己诶但都大,就退出
if (element > arr[child]) {
break;
}
//如果比子节点小就要将子节点的值上移
arr[parent] = arr[child];
parent = child;
child = 2 * child + 1; //先算出下移后的父节点的左孩子节点的索引
}
arr[parent] = element;
}
public static void swap(int[] arr, int a, int b) {
int tmp = arr[a];
arr[a] = arr[b];
arr[b] = tmp;
}
}
程序改变世界