简述堆排序
堆是一种做完全二叉树的数据结构。
常见的有两种堆:
大顶堆:每个节点的值都大于或者等于它的左右子节点的值。
小顶堆:每个节点的值都小于或者等于它的左右子节点的值。
根节点索引为i
父结点索引:(i-1)/2
左子节点索引为2i+1
右子节点索引为2i+2
所以
大顶堆:arr[i] >= arr[2i + 1] && arr[i] >= arr[2i + 2]
小顶堆:arr[i] <= arr[2i + 1] && arr[i] <= arr[2i + 2]
堆排序的基本步骤
1.首先将待排序的数组构造成一个大根堆,整个数组的最大值就是堆结构的顶端
2.将顶端的数与数组形式末尾的数交换,末尾的数为最大值,剩余待排序个数为n-1
3.将剩余的n-1个数再构造成大根堆,再将顶端数与n-1位置的数交换,反复执行,最终得到有序数组
package exer01;
import java.util.Arrays;
public class HeapTest {
public static void main(String[] args) {
int[] arr= {5,3,6,2,7,1,8,0,9,4};
heap_sort(arr, arr.length);
System.out.println(Arrays.toString(arr));
}
/**建堆和调整堆是不一样的,建堆要从第一个非叶节点进行循环,对每一个非叶节点下滤,调整堆只用对根节点下滤
*
* @param arr 存储堆的数组
* @param n 数组长度
* @param m 维护节点的下标
*/
public static void heapify(int[] arr,int n,int m)
{
int largest=m; //largest为一棵树中最大节点的索引,初始m为根节点
int left=m * 2 + 1; //该树的左孩子
int right=m * 2 + 2; //该树的右孩子
if(left < n && arr[left]>arr[largest])
largest=left;
if(right < n && arr[right]>arr[largest])
largest=right;
if (largest!=m)
{
swap(arr, largest, m);
heapify(arr, n, largest);
}
}
/**
* 建堆,排序
* @param arr
* @param n
*/
public static void heap_sort(int[] arr,int n) {
//建堆
for(int i=n/2-1; i>=0;i--) //n/2-1为i节点的父节点的下标
{
heapify(arr, n, i);
}
//排序
for (int i= n-1; i > 0; i--) {
swap(arr, i, 0);
heapify(arr, i, 0);
}
}
public static void swap(int[] arr,int i,int j)
{
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
图片转载https://blog.csdn.net/m0_52687456