一、基本思想:
- 对于给定的n个记录,初始时把这些记录看作一棵顺序存储的二叉树;
- 然后将其调整为一个大顶堆;
- 然后将堆的最后一个元素与堆顶元素(即二叉树的根节点)进行交换;
- 堆的最后一个元素即为最大元素;摘取
- 接着将前(n-1)个元素重新调整为一个大顶堆
- 再将堆顶元素与当前堆的最后一个元素进行交换后
- 得到第二大的元素
- 重复此过程,直到调整的堆中只剩一个元素位置
- 该元素为最小元素
- 此时可得到一个有序序列
二、分类及特点:
堆是具有以下性质的完全二叉树:
- 每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;
- 或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆
三、堆排序:
1. 大根堆:(数组升序排列)
public static void HeapAdjust(int[] array, int parent, int length) {
int temp = array[parent]; // temp保存当前父节点
int child = 2 * parent + 1; // 先获得左孩子
//大顶堆满足根节点大于所有孩子节点(比大的大),不满足则调整(比大的小)
while (child <= length) {
// 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点
if (child + 1 <= length && array[child] < array[child + 1]) {
child++;
}
// 如果孩子(大孩子)大于父节点(比大的小),则将孩子赋给父节点
if (temp < array[child])
array[parent] = array[child];
//否则,即比大的还大,则满足大顶堆,结束
else
break;
// 选取孩子结点的左孩子结点,继续向下筛选
parent = child;
child = 2 * child + 1;
}
array[parent] = temp;//将temp放到最终位置上
}
public static void heapSort(int[] array) {
//1.构建小顶堆
//从第一个非叶子结点从下至上,从右至左调整
for (int i = array.length / 2-1; i >= 0; i--) {
HeapAdjust(array, i, array.length - 1);
}
// 进行n-1次循环,完成排序
for (int i = array.length - 1; i >=0; i--) {
// 最后一个元素和第一元素进行交换
int temp = array[i];
array[i] = array[0];
array[0] = temp;
// 筛选 R[0] 结点,得到i-1个结点的堆
HeapAdjust(array, 0, i-1);
}
}
2. 小根堆:(数组降序排列)
public static void HeapAdjust(int[] array, int parent, int length) {
int temp = array[parent]; // temp保存当前父节点
int child = 2 * parent + 1; // 先获得左孩子
//小顶堆:根节点比子节点中小的还小,不满足此条件,则调整(即根节点比子节点中小的还大)
while (child <= length) {
// 如果有右孩子结点,左孩子大于右孩子,则指向右孩子(小孩子)
if (child + 1 <= length && array[child] > array[child + 1]) {
child++;
}
// 如果孩子(小孩子)小于父节点(比小的大),将孩子赋给父节点
if (temp > array[child])
array[parent] = array[child];
//若父节点比小孩子小,则直接结束
else
break;
// 选取孩子结点的左孩子结点,继续向下筛选
parent = child;
child = 2 * child + 1;
}
array[parent] = temp;//将temp放到最终位置上
}
public static void heapSort(int[] array) {
//1.构建小顶堆
//从第一个非叶子结点从下至上,从右至左调整
for (int i = array.length / 2-1; i >= 0; i--) {
HeapAdjust(array, i, array.length - 1);
}
// 进行n-1次循环,完成排序
for (int i = array.length - 1; i >0; i--) {
// 最后一个元素和第一元素进行交换
int temp = array[i];
array[i] = array[0];
array[0] = temp;
// 筛选 R[0] 结点,得到i-1个结点的堆
HeapAdjust(array, 0, i-1);
}
}
完成代码及测试:
1. 大根堆:
package sort;
/**
* @author hw
* @version 0.1
* @description 堆排序(大根堆)
* @date 2019/4/14
*/
public class TestMinHeapSort {
public static void HeapAdjust(int[] array, int parent, int length) {
int temp = array[parent]; // temp保存当前父节点
int child = 2 * parent + 1; // 先获得左孩子
//大顶堆满足根节点大于所有孩子节点(比大的大),不满足则调整(比大的小)
while (child <= length) {
// 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点
if (child + 1 <= length && array[child] < array[child + 1]) {
child++;
}
// 如果孩子(大孩子)大于父节点(比大的小),则将孩子赋给父节点
if (temp < array[child])
array[parent] = array[child];
//否则,即比大的还大,则满足大顶堆,结束
else
break;
// 选取孩子结点的左孩子结点,继续向下筛选
parent = child;
child = 2 * child + 1;
}
array[parent] = temp;//将temp放到最终位置上
}
public static void heapSort(int[] array) {
//1.构建小顶堆
//从第一个非叶子结点从下至上,从右至左调整
for (int i = array.length / 2-1; i >= 0; i--) {
HeapAdjust(array, i, array.length - 1);
}
// 进行n-1次循环,完成排序
for (int i = array.length - 1; i >=0; i--) {
// 最后一个元素和第一元素进行交换
int temp = array[i];
array[i] = array[0];
array[0] = temp;
// 筛选 R[0] 结点,得到i-1个结点的堆
HeapAdjust(array, 0, i-1);
}
}
public static void main(String[] args) {
int[] array = {5,4,9,8,7,6,0,1,3,2};
heapSort(array);
for (int i = 0; i < array.length; i++) {
System.out.print
(array[i] + " ");
}
}
}
运行结果:
2. 小顶堆:
package sort;
/**
* @author hw
* @version 0.1
* @description 堆排序(小根堆)
* @date 2019/4/14
*/
public class TestMaxHeapSort {
public static void HeapAdjust(int[] array, int parent, int length) {
int temp = array[parent]; // temp保存当前父节点
int child = 2 * parent + 1; // 先获得左孩子
//小顶堆:根节点比子节点中小的还小,不满足此条件,则调整(即根节点比子节点中小的还大)
while (child <= length) {
// 如果有右孩子结点,左孩子大于右孩子,则指向右孩子(小孩子)
if (child + 1 <= length && array[child] > array[child + 1]) {
child++;
}
// 如果孩子(小孩子)小于父节点(比小的大),将孩子赋给父节点
if (temp > array[child])
array[parent] = array[child];
//若父节点比小孩子小,则直接结束
else
break;
// 选取孩子结点的左孩子结点,继续向下筛选
parent = child;
child = 2 * child + 1;
}
array[parent] = temp;//将temp放到最终位置上
}
public static void heapSort(int[] array) {
//1.构建小顶堆
//从第一个非叶子结点从下至上,从右至左调整
for (int i = array.length / 2-1; i >= 0; i--) {
HeapAdjust(array, i, array.length - 1);
}
// 进行n-1次循环,完成排序
for (int i = array.length - 1; i >0; i--) {
// 最后一个元素和第一元素进行交换
int temp = array[i];
array[i] = array[0];
array[0] = temp;
// 筛选 R[0] 结点,得到i-1个结点的堆
HeapAdjust(array, 0, i-1);
}
}
public static void main(String[] args) {
int[] array = {5,4,9,8,7,6,0,1,3,2};
heapSort(array);
for (int i = 0; i < array.length; i++) {
System.out.print
(array[i] + " ");
}
}
}
测试结果: