堆的定义
n个元素的序列{k1,k2,k3, ... ,kn},当且仅当满足以下关系时,称之为堆。
堆排序要点
建堆:将n个元素建成堆。排序:输出堆顶元素后,调整剩余元素,使之成为大根堆;继续输>出堆顶,继续调整,依此类推。
(一)筛选:调整堆使之成为大根堆或小根堆输出堆顶元素后,将堆底元素送入堆顶,由于根结点不满足堆的性质,此时堆被破坏,而根结点的左右子树仍然是堆。然后,将根结点与左右子树,较大或者较小的进行比较。如果与左子树交换,左子树破坏;如果与右子树交换,右子树破坏。继续对不满足堆性质>的子树就行上述操作,直到叶子结点。
排序的过程就是不断输出堆顶并进行筛选的过程。
(二)建堆:建堆的过程就是从底向上对每一个非叶子结点进行一次筛选即可。
时间和空间复杂度
每输出一次堆顶元素需要进行一次调整,每次调整需要的比较次数>为logn,时间复杂度O(logn),n次输出总共需要的比较次数为O(nlogn)。空间复杂度为O(n)。
代码实现
public class HeapSort {
// 已知除了arr[low],其他元素满足堆的定义
public static void heapAdjust(int[] arr, int low, int high) {
int temp = arr[low];
for (int i = low * 2 + 1; i < high; i = i * 2 + 1) {
if ((i + 1) < high && arr[i] < arr[i + 1]) {
i++;
}
if (temp < arr[i]) {
arr[low] = arr[i];
low = i;
} else {
break;
}
}
arr[low] = temp;
System.out.println("adjust:"+JSON.toJSONString(arr));
}
public static void heapSort(int[] arr) {
int n = arr.length;
//初始化堆,从下向上建堆
for (int i = n / 2 - 1; i >= 0; i--) {
heapAdjust(arr, i, n);
}
System.out.println("done");
//排序,输出头节点,把最后叶子结点的值赋值给头节点,调整
for (int i = n - 1; i > 0; i--) {
int head = arr[0];
arr[0] = arr[i];
arr[i] = head;
heapAdjust(arr, 0, i);
}
}
public static void main(String[] args) {
int[] arr = {0,1,2,3,4,5,6,7,8,9,10};
heapSort(arr);
System.out.println(JSON.toJSONString(arr));
}
}