堆排序
介绍
堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最好最坏,平均时间复杂度均为O(nlogn),是不稳定排序。
基本思想
- 将待排序序列构造成一个大顶堆(父结点大于两个子结点)
- 此时,整个序列的最大值就是堆顶的根结点
- 将其与末尾元素进行交换,此时末尾就为最大值
- 将末尾这个最大值用排除堆之外,然后将剩余n-1个元素重新构成一个堆,这样就会得到n个元素的次小值,反复执行,按顺序排除出堆的元素就能组成一个有序队列了。
问题描述
给定一个数组,使用堆排序从小到大排序好,或者可以理解为实现小顶堆(父结点小于两个子结点)。
String[] s = {“S”,“O”,“R”,“T”,“E”,“X”,“A”,“M”,“P”,“L”,“E”};
主要方法及其原理:
(1)根据原数组构造出一个堆(createHeap(Comparable[] source, Comparable[] heap)),返回值为空,参数分别是要传入的数组和堆的数组,将传入的数组复制到堆数组中,并用下沉算法调整堆中的元素
(2)下沉算法(sink(Comparable [] heap,int target,int range)),返回值空,target是要下沉调整的元素,range是调整的范围,可以看成是不断变换的堆数组的长度
(3)排序方法(sort(Comparable[] cource)),参数是要传入的数组,每次循环将最大值和堆中最大索引处的值交换,并且排除最大索引处的值,使其不再参与下沉,排除后的值仍在堆中并且处于的数组中的位置没有变,直到循环结束,排除后的值就是按照从小到大的顺序排序,最后再将堆复制到原数组中。
具体操作看代码
代码实现
public class HeapSort {
//判断heap堆中索引i处的元素是否小于索引j处的元素
private static boolean less(Comparable[] heap, int i, int j){
return heap[i].compareTo(heap[j])<0;
}
//-----------------------------------------------------------------
//交换heap堆中两指定索引处的值
private static void exchange(Comparable[] heap, int i, int j){
Comparable temp = heap[i];
heap[i] = heap[j];
heap[j] = temp;
}
//-----------------------------------------------------------------
//根据原数组source构造出堆heap,对堆中元素做下沉跳整
private static void createHeap(Comparable[] source, Comparable[] heap){
//把source中的元素拷贝到heap中,heap中元素形成一个无需堆
System.arraycopy(source,0,heap,1,source.length);
//对堆中的元素做下沉调整(从长度的一半开始往索引1处开始扫描)
for(int i = (heap.length)/2; i>0; i--){
sink(heap,i, heap.length-1);
}
}
//-----------------------------------------------------------------
//对source数组中的数据从小到大排序
public static void sort(Comparable[] source){
//构建堆
Comparable[] heap = new Comparable[source.length+1];
createHeap(source,heap);
//定义一个变量记录为排序的元素中最大的索引
int N = heap.length-1;
//通过循环交换1索引处和排序的元素中最大的索引处的元素
while(N!=1){
//交换元素
exchange(heap,1,N);
//排序交换后最大元素所在的索引,让它不再参与下沉
N--;
//对索引1处的元素进行堆的下沉调整
sink(heap,1,N);
}
//
System.arraycopy(heap,1,source,0,source.length);
}
//-----------------------------------------------------------------
//在heap堆中,对target处的元素做下沉,让小的往下走,范围是0~range,
private static void sink(Comparable[] heap, int target, int range){
while(2*target<=range){
//找出当前结点的较大的子节点
int max;
if(2*target+1<=range){ //在当前左右结点都存在的情况下比较
if(less(heap,2*target,2*target+1)){
max = 2*target+1;
}else{
max = 2*target;
}
}else{
max = 2*target;
}
//2、比较当前结点的值和较大子结点的值
if (!less(heap, target, max)) {
break;
}
exchange(heap,target,max);
target = max;
}
}
}
测试代码
public static void main(String[] args) {
String[] s = {"S","O","R","T","E","X","A","M","P","L","E"};
HeapSort.sort(s);
System.out.println(Arrays.toString(s));
}
结果:
[A, E, E, L, M, O, P, R, S, T, X]