核心点:堆调整
如何形成最小堆/最大堆,那就先需要了解最小堆/最大堆的概念。
最大堆(大根堆)要求根节点的关键字既大于或等于左子树的关键字值,又大于或等于右子树的关键字值,且要求是完全二叉树。
调整过程:
- 保存当前节点值,当前节点为父节点;
- 通过父节点找到子节点;
- 如果子节点不存在,退出;否则,判断左右孩子中的大值节点,记录该节点;
- 如果父节点大于等于该大值节点,退出;否则,将大值节点与其父节点值交换,并将该子节点设为父节点,找到该节点的子节点;跳至3继续执行。
import java.util.Arrays;
public class HeapSort {
public static void main(String[] args) {
int[] s = new int[] { 5, 1, 6, 7, 3, 2, 4, 9, 10, 8 };
HeapSort hs = new HeapSort();
hs.sort(s);
}
public void sort(int[] s) {
for (int i = s.length / 2 - 1; i >= 0; i--) {
adjustHeap(s, i, s.length);// 初始建立最大堆
}
System.out.println(Arrays.toString(s));
for (int i = s.length - 1; i > 0; i--) {
swap(s, 0, i);// 最大值调整到最后,其实得出的是升序
adjustHeap(s, 0, i);// 每次从根节点向下做出调整,由于每次都会得出一个有序数,所以i--
System.out.println(Arrays.toString(s));
}
}
public void adjustHeap(int[] s, int parent, int length) {
int tmp = s[parent];// 保存当前节点值
int child = 2 * parent + 1;// 左孩子
while (child < length) {
if (child + 1 < length && s[child] < s[child + 1]) {// 找左右孩子中的大值节点,如果是右孩子执行
child++;
}
if (s[parent] >= s[child]) {// 如果符合条件,退出调整
break;
} else {
s[parent] = s[child];
parent = child;
child = 2 * child + 1;// 继续探测孩子节点是否符合最大或者最小堆
}
s[parent] = tmp;// 如果发生调整则进行值交换,此时的parent值已经是其孩子节点
}
}
public void swap(int[] s, int a, int b) {
int tmp = s[a];
s[a] = s[b];
s[b] = tmp;
}
}
执行输出:
[10, 9, 6, 7, 8, 2, 4, 1, 5, 3]
[9, 8, 6, 7, 3, 2, 4, 1, 5, 10]
[8, 7, 6, 5, 3, 2, 4, 1, 9, 10]
[7, 5, 6, 1, 3, 2, 4, 8, 9, 10]
[6, 5, 4, 1, 3, 2, 7, 8, 9, 10]
[5, 3, 4, 1, 2, 6, 7, 8, 9, 10]
[4, 3, 2, 1, 5, 6, 7, 8, 9, 10]
[3, 1, 2, 4, 5, 6, 7, 8, 9, 10]
[2, 1, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
需要注意的是:最大堆每次将堆中最大值调整到数组尾部,所以得出的序列为升序序列。