1 堆的概念
堆排序中的"堆"是指二叉堆,是一棵被完全填满的二叉树(完全填满不是指满二叉树),也就是完全二叉树,深度为logN。
-
完全二叉树
- 图示
以层级遍历如果出现空节点,后面节点都为空就是一棵完全二叉树。
最大堆,最小堆
- 父节点的值大于左右节点值的堆称为最大堆,也就是说根节点的值是树中的最大值
- 父节点的值小于左右节点值的堆称为最小堆,也就是说根节点的值是树中的最小值图示
图示
最大堆 最小堆
堆排序是通过最大堆或是最小堆进行排序的
2 堆排序基本思路
完全二叉树可以由一个数组去实现
因此一个堆可以由一个数组表示,并且在数组表示的形式有一定的规律:
约定 父节点在数组中的索引用 k 表示 左节点的索引为 m 右节点的索引为 n
- 左节点的索引为 m= 2*k+1
- 右节点的索引为 n = 2*k+2
- 父节点的索引为 k= (m -1)/2 或者 (n-1)/2
升序的实现
由上述最大堆定义可知:根节点保存树中数据的最大值 ,所以可以将根节点与最后一个节点的值互换,最后一个节点保存了最大值,然后使 除最后一节点的堆再次形成最大堆,根节点可以得到第二大的值,然后与新的最大堆的最后一个数据互换,以此类推得到一个升序的有序队列。
具体过程
①将数据存入数组
②将数组数据初始化为最大堆结构
③将根节点数据与最后一节点数据交换
④调整堆使剩下的再次形成最大堆
。。。。。。直到所需调整的堆的大小为1,即无需再排序
堆排序减少了大量重复的排序,没有受到影响的子树不会去深度访问
public class HeapSortTest {
public static void sort(int []arr){
//构建最大堆(初始化)从最后一个非叶子节点开始
for(int i=(arr.length-1)/2;i>=0;i--){
partAdjust(arr,i,arr.length);
}
//将最大值交换到末尾 并调整剩下成为最大堆
for(int j=arr.length-1;j>=0;j--){
swap(arr,0,j);
partAdjust(arr,0,j);
}
}
//局部调整 使父节点的值比左右节点大
public static void partAdjust(int []arr,int i,int length){
int temp=arr[i];
//每次都跳到左节点
for( int k=2 * i + 1;k<length;k=2*k+1){
//选出左右节点较大的值 k+1<length原因是如果不存在右节点k+1会越界
if (k+1<length&&arr[k] <arr[ k+1]) {
k++;
}
//如果子节点中的值比父节点大 将值赋给父节点 并且调整节点指向下一个左节点
if(temp<arr[k]){
arr[i]=arr[k];
i=k;
}
//在最大堆的条件下 如果父节点值比子节点都大,就不需要再往下比较
else break;
}
//最终temp存放的值的位置
arr[i]=temp;
}
public static void swap(int[]arr,int a,int b){
int temp =arr[a];
arr[a]=arr[b];
arr[b]=temp;
}
//main函数
public static void main(String[] args) {
int []arr1= {10,1,7,8,4,7,4,8,3,5,9};
int arr[]=new int[100000];
int j=0;
for(int i=arr.length-1;i>=0;i--){
arr[i]=j;
j++;
}
sort(arr1);
System.out.println(Arrays.toString(arr1));
System.out.println("----------");
System.out.println(new Date().getTime());
sort(arr);
System.out.println(new Date().getTime());
System.out.println(Arrays.toString(arr));
}
}
//output
[1, 3, 4, 4, 5, 7, 7, 8, 8, 9, 10]
----------
1556102486756
1556102486786
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22。。。。。。]
在构建最大堆,是从最后一个非叶子节点开始 所以是从 (最后一个元素的索引 - 1 ) / 2 开始
for(int i=(arr.length-1)/2;i>=0;i--){
partAdjust(arr,i,arr.length);
}