堆排序是利用“堆”这种数据结构而设计的一种排序算法,它是一种选择排序。
堆排序的基本思想:
1、将待排序的含n个元素的序列构造成一个堆(至于用大根堆还是小根堆,自己酌情用),整个序列的根节点就是最值节点。
2、将该最值节点与末尾节点交换,此时末尾节点就是最值节点。
3、不处理末尾得到的最值节点,将剩余n-1节点重新构造成一个堆,重复以上步骤,取出每个堆中的最值节点,就能得到一个有序序列。
下面我用java代码按步骤写一下这个排序过程
1.构造一个序列,我用数组,在里面填10个50以下的随机数。
int[] arr = new int[10];
Random rd = new Random();
for(int i=0;i<arr.length;i++){
arr[i] = rd.nextInt(50);// 用50及以下的随机整数作为数组元素
}
2.写一个方法,该方法能将数组元素构造成一个大根堆,利用递归的方式
/**
* 构造大根堆
* @param arr 要排序的数组
* @param length 当前要调整的元素个数
* @param startIndex 当前要调整的起始位置
*/
private static void toMaxHead(int[] arr, int length, int index) {
// 获取左右子节点的索引
int leftNodeIndex = 2*index+1;
int rightNodeIndex = 2*index+2;
// 获取最大节点所对应的的索引
int maxIndex = index; // 用于获取最大节点所对应的的索引
if(leftNodeIndex < length && arr[maxIndex] < arr[leftNodeIndex]){
maxIndex = leftNodeIndex;
}
if(rightNodeIndex < length && arr[maxIndex] < arr[rightNodeIndex]){
maxIndex = rightNodeIndex;
}
// 如果index已经改变,索引对应的节点交换位置
if(maxIndex != index){
int t = arr[index];
arr[index] = arr[maxIndex];
arr[maxIndex] = t;
toMaxHead(arr, length, maxIndex); // 递归
}
}
3.main中循环调用该方法,获得初始大根堆
// 定义开始调整的位置
int startIndex = (arr.length-1)/2;
// 第一次循环调整
for(int i = startIndex;i>=0;i--){
toMaxHead(arr,arr.length,i);
}
4.将第一次调整后的大根堆的根节点和最后一个节点进行交换,然后继续循环处理剩下的节点
for(int i = arr.length-1;i>0;i--){
int t = arr[0];
arr[0] = arr[i];
arr[i] = t;
// 交换之后,在循环中随着i的减小缩小数组长度
toMaxHead(arr, i, 0); // 继续递归将剩余i个数组元素排成大根堆
}
完整代码:
public class StackSort {
public static void main(String[] args) {
int[] arr = new int[10];
Random rd = new Random();
for(int i=0;i<arr.length;i++){
arr[i] = rd.nextInt(50);// 用50及以下的随机整数作为数组元素
}
System.out.println("排序前:"+Arrays.toString(arr));
// 定义开始调整的位置
int startIndex = (arr.length-1)/2;
// 第一次循环调整
for(int i = startIndex;i>=0;i--){
toMaxHead(arr,arr.length,i);
}
// 将第一次调整后的大根堆的根节点和最后一个节点进行交换
for(int i = arr.length-1;i>0;i--){
int t = arr[0];
arr[0] = arr[i];
arr[i] = t;
// 交换之后,在循环中随着i的减小缩小数组长度
toMaxHead(arr, i, 0); // 继续递归将剩余i个数组元素排成大根堆
}
System.out.println("排序后:"+Arrays.toString(arr));
}
/**
* 构造大根堆
* @param arr 要排序的数组
* @param length 当前要调整的元素个数
* @param startIndex 当前要调整的起始位置
*/
private static void toMaxHead(int[] arr, int length, int index) {
// 获取左右子节点的索引
int leftNodeIndex = 2*index+1;
int rightNodeIndex = 2*index+2;
// 获取最大节点所对应的的索引
int maxIndex = index; // 用于获取最大节点所对应的的索引
if(leftNodeIndex < length && arr[maxIndex] < arr[leftNodeIndex]){
maxIndex = leftNodeIndex;
}
if(rightNodeIndex < length && arr[maxIndex] < arr[rightNodeIndex]){
maxIndex = rightNodeIndex;
}
// 如果index已经改变,索引对应的节点交换位置
if(maxIndex != index){
int t = arr[index];
arr[index] = arr[maxIndex];
arr[maxIndex] = t;
toMaxHead(arr, length, maxIndex); // 递归
}
}
}
运行情况: