标签:void sort 一个 [] 简单 时间复杂度 时间 子节点 位置
堆排序是利用堆这种数据结构而设计的一种排序算法,属于选择排序,它的最坏、最好、平均复杂度均为O(Nlog2^N),属于不稳定排序;
堆是具有以下性质的完全二叉树:每个节点的值都大于或等于其左右孩子节点的值,称为大顶堆;每个节点的值都小于或等于其左右孩子节点的值,称为小顶堆;
用简单的公式描述一下堆的定义:
大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
堆排序的基本思想:将待排序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆),此时,整个序列的最大值就是堆顶的根节点。将其与序列的末尾元素进行交换,此时序列末尾就为最大值。然后将剩余n-1个元素重新构造一个堆,这样可以得到n个元素中的次小值。如此反复执行,便能得到一个有序序列了。
总结来说:
1.将无序序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
2.将顶堆元素与序列末尾元素交换,将最值元素沉到数组末端;
3.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列完全有序。
示例代码:
public class Test {
public static void main(String[] args) {
int[] arr = {6, 3, 8, 2, 9, 1};
System.out.println("排序前数组为:");
for(int i : arr) {
System.out.print(i + ", ");
}
System.out.println();
sort(arr);
System.out.println("排序后数组为:");
for(int i : arr) {
System.out.print(i + ", ");
}
}
public static void sort(int[] arr) {
for(int i=arr.length/2-1;i>=0;i--) { //构建大顶堆
adjustHeap(arr,i, arr.length); //从第一个非叶子节点从下至上,从右至左调整结构
}
for(int j=arr.length-1;j>0;j--) { //调整堆结构+交换堆顶元素与序列末尾元素
swap(arr, 0, j);
adjustHeap(arr, 0, j);
}
}
public static void adjustHeap(int[] arr, int i, int length) {
int tmp = arr[i]; //先取出当前父节点元素i
for(int k=i*2+1;k<length;k=k*2+1) { //从当前元素的左子节点开始
if(k+1 < length && arr[k] < arr[k+1]) { //如果左子节点小于右子节点,k指向右子节点
k++;
}
if(arr[k] > tmp) { //如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
arr[i] = arr[k];
i = k;
}
}
arr[i] = tmp; //将tmp值放到最终位置
}
public static void swap(int[] arr, int a, int b) {
int tmp = arr[a];
arr[a] = arr[b];
arr[b] = tmp;
}
}
堆排序的时间复杂度为O(Nlog2^N),空间复杂度为O(1),稳定性不好。
标签:void sort 一个 [] 简单 时间复杂度 时间 子节点 位置
原文地址:https://www.cnblogs.com/yuanfei1110111/p/10203402.html