文章流程:
思路——代码——分析——改进
【思路】
堆排序有两种,一种利用堆的特性,先构建最大堆,每次得到最大堆的堆顶元素;另一种是直接原地使用堆排序。
原地堆排序:
将数组构建成堆,交换数组的第一个元素和最后一个元素。依次对除去最后的元素的剩下数组进行排序。
【代码】
原地排序:
public class Main{
public static void main(String[] args){
int arr[] = {...};
heapSort(arr,arr.length);
}
public static void heapSort(int[] arr,int n){
//heapify
for(int i = (n-1)/2;i>=0;i--){//(n-1)/2是最后一个非叶子节点
shiftDown(arr,n,i);
}
for(int i = n-1;i>0;i--){
swap(arr,i,0);
shifDown(arr,i,0);
}
}
public static void shiftDown(int[] arr,int n,int k){
while(2*k+1<=n-1){//2*k+1表示k的左孩子
int j = 2*k+1;
if(j+1<n && arr[j+1]>arr[j])
j+=1;
if(arr[k]>=arr[j])
break;
swap(arr,k,j);
k = j;
}
}
}
堆外排序:
public class Main{
public static void main(String[] args){
int[] arr = {23,2,4,1,5,7};
MaxHeap mh = new MaxHeap(arr);
for(int i = arr.length-1;i>=0;i--){
arr[i] = mh.extractMax();
}
for(int i:arr){
System.out.println(i);
}
}
static class MaxHeap{
private int[] data;
private int capacity;
private int count;
MaxHeap(int capacity){
data = new int[capacity+1];
count = 0;
this.capacity = capacity;
}
MaxHeap(int[] arr){
int n = arr.length;
data= new int[n+1];
capacity = n;
for(int i = 0;i<=n-1;i++){
data[i+1] = arr[i];
}
for(int i = n/2;i>=1;i--){
shiftDown(i);
}
count = n;
}
void shiftDown(int k){
while(2*k<=count){
int j = 2*k;
if(j+1<=count && data[j+1]>data[j])
j += 1;
if(data[k]>=data[j])
break;
swap(data,k,j);
k = j;
}
}
int extractMax(){
int max = data[1];
swap(data,1,count);
count--;
shiftDown(1);
return max;
}
}
public static void swap(int arr[],int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
【分析】
堆排序时间复杂度O(nlgn),空间复杂度O(1)。不稳定排序。
【改进】
。。。