堆排序一共有两种风格
都以升序排序为例
- 将待排序数组建成一个小堆,每次取堆顶元素后放入一个数组中。然后再向下调整继续进行。
- 把数组建成一个大堆,堆顶就是当前数组的最大值,然后把堆顶元素和最后一个元素进行互换,再把最后一个元素从堆里面删除,
第一种:
public static void main(String[] args) {
int[] arr = {5, 3, 6, 8, 9, 1, 2};
System.out.println((Arrays.toString(insertsort(arr))));
}
public static int[] insertsort(int[] arr) {
PriorityQueue<Integer> queue = new PriorityQueue<>();//首先建立一个小堆
for (int i = 0; i < arr.length; i++) {//再将待排序数组中的每个元素入队列
queue.offer(arr[i]);
}
int[] array = new int[arr.length];//再创建一个新的数组来存放堆顶元素
for (int i = 0; i < array.length; i++) {//循环出堆顶元素放到新数组中
array[i] = queue.poll();
}
return array;
}
第二种:
public static void main(String[] args) {
int[] arr = {5, 3, 6, 8, 9, 1, 2};
insertsort(arr);
System.out.println(Arrays.toString(arr));
}
public static void insertsort(int[] arr) {
//首先建大堆
creatheap(arr);
for(int i = 0;i<arr.length;i++){//然后循环交换堆顶元素和堆尾元素
swap(arr,0,arr.length-1-i);//注意交换的是堆顶元素和堆尾元素,而非数组尾元素。
//交换完之后还要进行向下调整
shiftdown(arr,0,arr.length-1-i);//交换完之后此时堆中的有效元素就要少一个,
}
}
public static void swap(int[] arr,int i,int j){
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
private static void creatheap(int[] arr) {
int index = (arr.length-1-1)/2;//从倒数第一个非叶子节点开始进行向下调整
for(;index>=0;index--){
shiftdown(arr,index,arr.length);
}
}
private static void shiftdown(int[] arr, int index, int heaplength) {
int parent = index;
int child = parent*2+1;
while(child<heaplength){
if(child+1<heaplength&&arr[child]<arr[child+1]){
child = child+1;
}
if(arr[parent] < arr[child]){
int tmp = arr[parent];
arr[parent] = arr[child];
arr[child] = tmp;
}else{
break;
}
parent = child;
child = parent*2+1;
}
}
第一种风格有一点缺陷就是需要开辟额外的空间,而第二种则不需要。
堆排序也是不稳定排序。因为在向下调整的时候会打乱顺序。