关于快速排序的算法参考 经典算法(4)一文搞懂什么是 快速排序;关于二分法的算法可以参考另一篇博客 经典算法(2)一文搞懂二分法查找(循环和递归两种方式); 有关冒泡排序的算法参考 经典算法(1)冒泡排序及其优化
一、堆排序介绍
百度百科是这样介绍堆排序的:
二、堆排序的算法思想
-
构造一个大根堆
将堆的末端子结点进行调整,使得子结点永远小于父结点;整个序列的最大值就是堆顶的根结点。即每个结点的值都大于其左孩子和右孩子结点的值。 -
堆排序
移除位在第一个数据的根结点,将其与末尾元素进行交换,末尾就是最大值;
将剩余n-1个元素重构造成一个堆,这样就会得到n个元素的次大值,反复 执行,就得到一个有序序列
三、堆排序的过程图解
以 30,60,0,50,80,20,10 为例进行说明
第一步:把放在数组里的元素看成一个二叉树,对该二叉树进行调整,使之变成一个大根堆。
思路: 从最后一个非叶子结点开始,从左到右,从下到上进行调整
经过上述步骤,我们得到了一个大根堆
第二步:将堆顶元素与与最后一个数交换,将最大元素下沉到数组末尾,然后将剩余的数再构造成一个大根堆。如此循环反复执行
第1次:删除结点80,将80与10进行交换
第2次:删除结点60,将60与0进行交换
第3次:删除结点50,将50与0进行交换
第4次:删除结点30,将30与0进行交换
第5次:删除结点20,将20与0进行交换
第6次:删除结点10,将10与0进行交换
扫描二维码关注公众号,回复:
8493763 查看本文章
四、代码实现
public class HeapSort {
public static void main(String[] args) {
System.out.println("输入要排序的值,输入的每个值用逗号隔开:");
Scanner input = new Scanner(System.in);
String str = input.nextLine();
// 将字符串按照","拆分成字符串数组
String[] strArray = str.split(",");
// 新建数组用来存储拆分出来的每个值
int[] array = new int[strArray.length];
// 给数组循环遍历赋值
for (int i = 0; i < strArray.length; i++) {
array[i] = Integer.parseInt(strArray[i]);
}
System.out.println("排序前的数组:" + Arrays.toString(array));
// 排序
heapSort(array);
System.out.println("排序后的数组:" + Arrays.toString(array));
}
/**
* 堆排序
*
* @param array 需要进行排序的数组
*/
private static void heapSort(int[] array) {
// 把无序的数组构建成大根堆(每个结点的值都大于其左孩子和右孩子结点的值)
for (int i = array.length / 2 - 1; i >= 0; i--) {
downAdjust(array, i, array.length);
}
System.out.println("调整以后的堆数组: " + Arrays.toString(array));
// 循环将堆顶元素与末尾元素交换,将最大元素下沉到末端,重新调整堆,产生新的堆顶。直到整个数组有序
for (int i = array.length - 1; i > 0; i--) {
// 最后一个元素与第一个元素进行交换
int temp = array[i];
array[i] = array[0];
array[0] = temp;
// 下沉调整最大堆
downAdjust(array, 0, i);
}
}
/**
* 将无序数组构造成一个大根堆
*
* @param array 待调整的堆数组
* @param parentIndex 父结点的索引
* @param length 需要调整的堆数组的大小
*/
private static void downAdjust(int[] array, int parentIndex, int length) {
// 取出父结点的值,保存在临时变量
int temp = array[parentIndex];
// childIndex = 2 * parentIndex + 1 是parentIndex结点的左孩子结点
for (int childIndex = 2 * parentIndex + 1; childIndex < length; childIndex = 2 * childIndex + 1) {
if (childIndex + 1 < length && array[childIndex] < array[childIndex + 1]) {
// childIndex 指向右孩子结点
childIndex++;
}
// 如果子结点值大于父结点的值,把较大的值赋值给当前结点
if (array[childIndex] > temp) {
array[parentIndex] = array[childIndex];
parentIndex = childIndex;
} else {
break;
}
}
// 当循环结束以后,以parentIndex为父结点的树的最大值,放在了最顶端
array[parentIndex] = temp;
}
}
代码执行结果: