选择排序的基本思想:每一趟 (例如第i趟,i = 0,1,…)在后面第n-i个待排序元素中选出最小元素作为有序序列的第i个元素,直到第n-1趟结束后,所有元素有序。在这里,我们介绍两种具体的选择排序算法:直接选择排序与堆排序。
堆排序的核心是堆调整算法。首先根据初始输入数据,利用堆调整算法shiftDown()形成初始堆;然后,将堆顶元素与堆尾元素交换,缩小堆的范围并重新调整为堆,如此往复。堆排序是一种不稳定的排序算法,其实现如下:
package keking.sort;
/**
* Title: 堆排序(选择排序),升序排序(最大堆),依赖于初始序列
* Description: 现将给定序列调整为最大堆,然后每次将堆顶元素与堆尾元素交换并缩小堆的范围,直到将堆缩小至1
* 时间复杂度:O(nlgn)
* 空间复杂度:O(1)
* 稳 定 性:不稳定
* 内部排序(在排序过程中数据元素完全在内存)
* @author keking
*/
public class HeapSort {
public static void heapSort(int[] target){
//调整数组为最大堆
for(int i = target.length / 2 - 1; i >= 0; i--){
adjustHeap(target, i, target.length - 1);
}
//交换根节点和最后一个元素,完成从小到大的排序
for(int i = target.length - 1; i > 0; i--){
int temp = target[i];
target[i] = target[0];
target[0] = temp;
adjustHeap(target, 0, i);
}
}
//将数组调整为最大堆,根节点的值为最大值
private static void adjustHeap(int[] target, int parent, int length){
int temp = target[parent];
int child = parent * 2 + 1; //根节点的左子节点下标
while(child < length){
if(child + 1 < length && target[child + 1] > target[child]){
child ++; //右子节点值大,下标指向右子节点
}
if(target[child] < temp){
break; //左右子节点都小于根节点,跳出
}
target[parent] = target[child]; //子节点大于根节点,赋值给根节点
//重新调整子节点下的节点
parent = child;
child = parent * 2 + 1;
}
//如果根节点和子节点交换过,parent为子节点的下标,将原始根节点的值赋值给子节点
//如果根节点没有和子节点交换过,根节点还是原来的值
target[parent] = temp;
}
}