堆排序
前言
- 完全二叉树定义: 除了最后一层之外每一层都被完全填充,并且所有节点都向左对齐
- 堆排序: 大顶堆表示根节点的值都不小于其左右孩子 小顶堆表示根节点的值都不大于其左右孩子 可知大顶堆的根节点是整个数组中最大的。
- 二叉树父子节点的关系 根节点A 左孩子节点就是2A+1 右孩子节点就是2A+2
- 堆排序流程: 通过去构造大顶推每次构造之后最大元素在堆顶,然后把堆顶元素放在数组的末尾,不断的构造堆、交换、构造堆交换。完成数组的排序
排序流程
动图
代码
//建堆
public static void buildHeap(int arr[],int curr,int size){
if(curr<size){
//左子树位置
int left=2*curr+1;
//右子树位置
int right=2*curr+2;
int max=curr;
if(left<size){
//左子树比当前节点大。记录位置
if(arr[max]<arr[left]){
max=left;
}
}
//右子树比当前节点大。记录位置
if(right<size){
if(arr[max]<arr[right]){
max=right;
}
}
if(max!=curr){
//如果最大的不是根元素位置,那么就交换
int temp=arr[curr];
arr[curr]=arr[max];
arr[max]=temp;
//以max节点为父节点继续建堆
buildHeap(arr,max,size);
}
}
}
//从数组末尾开始去构建堆,实现整个数组符合一个大顶堆。
public static void maxHeap(int arr[],int size){
for(int j=size-1;j>=0;j--){
buildHeap(arr,j,size);
}
}
public static void heapSort(int arr[]){
for (int i = 0; i < arr.length; i++) {
maxHeap(arr,arr.length-i);
//将堆顶元素与数组最后位置交换。完成一次排序流程
int temp=arr[0];
arr[0]=arr[arr.length-1-i];
arr[arr.length-1-i]=temp;
}
}
复杂度分析
堆排序是一种选择排序,整体主要由构建初始堆+交换堆顶元素和末尾元素并重建堆两部分组成。其中构建初始堆经推导复杂度为O(n),在交换并重建堆的过程中,需交换n-1次,而重建堆的过程中,根据完全二叉树的性质,[log2(n-1),log2(n-2)...1]逐步递减,近似为nlogn。所以堆排序时间复杂度最好和最坏情况下都是O(nlogn)级。