参考书籍:《算法4》。学习视频:尚硅谷Java数据结构与java算法(Java数据结构与算法)_哔哩哔哩_bilibili
堆排序的定义
- 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均的时间复杂度均为O(nlogn),它也是不稳定排序.
- 堆是具有一下性质的完全二叉树:每个结点的值都大于或等于其左右子结点的值,称为大顶堆,注意:没有要求结点的左子结点的值和右子结点的值的大小关系。
- 每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆
大顶堆的举例
对堆中结点按层数进行排序,映射到数组中就是arr={70,50,40,30,35,25,20,10,20};
大顶堆特点:arr[i]>=arr[2*i+1]&&arr[i]>=arr[2*i+2] // i对应结点下标,i从0开始编号
小顶堆举例
同理 ——小顶堆:arr[i]<=arr[2*i+1]&&arr[i]<=arr[2*i+2] // i对应结点下标, i从0开始编号
总结:一般升序采用大顶堆,降序采用小顶堆.
堆排序的思想
- 将待排序序列构造成一个大顶堆
- 此时,整个序列的最大值就是堆顶的根结点
- 将其与末尾元素进行交换,此时末尾就为最大值
- 然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。
在构建大顶堆的过程中,元素的个数逐渐减少,最后就得到一个有序序列了
代码实现
import java.util.Arrays;
public class test{
public static void main(String[] args)
{
int arr[]= {4,6,8,5,9,20,99,321,31};
heapSort(arr);
}
//编写一个堆排序的方法
public static void heapSort(int arr[])
{
System.out.println("堆排序");
/*
* //测试 adjustheap(arr,1,arr.length);
* System.out.println("第一次排序:"+Arrays.toString(arr));//4,9,8,5,6
*
* adjustheap(arr,0,arr.length);
* System.out.println("第二次排序:"+Arrays.toString(arr));//9,6,8,5,4
*
*/
//将无序序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆
for(int i=arr.length-1;i>=0;i--)
{
adjustheap(arr,i,arr.length);
}
System.out.println("成堆:"+Arrays.toString(arr));
//堆顶元素与末尾元素交换,将最大元素处理到数组末端
//重新调整堆结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整加交换步骤,直到整个序列有序
for(int j=arr.length-1;j>0;j--)
{
//执行交换
int temp=arr[j];
arr[j]=arr[0];
arr[0]=temp;
adjustheap(arr,0,j);
}
System.out.println("数组="+Arrays.toString(arr));
}
//将一个数组(二叉树,调成一个大顶堆)
/**
* 方法的功能:完成 将 以 i 对应的非叶子结点的树调整成大顶堆(父亲比两儿子大)
* @param arr待操作数组int arr[]={4,6,8,5,9};=>i=1=>adjustheap=>{4,9,8,5,6};
* 如果我们再次调用adjustheap 传入的是i=0=>{4,9,8,5,6}=>{9,6,8,5,4};
* @param i 表示非叶子结点在数组中的索引
* @param length length表示对多少个元素进行调整,length 是在逐渐的减少
*/
public static void adjustheap(int arr[],int i,int length)
{
int temp=arr[i];//先取出当前位置的值,保存在临时变量
//开始调整
for(int k=i*2+1;k<length;k=k*2+1)//第一个k代表i结点的左子结点,k=k*2+1代表左子结点的左子结点
{
if(k+1<length&&arr[k]<arr[k+1])
{
k++;//k指向右子结点,找左右结点谁大
}
if(arr[k]>temp)//如果子结点大于父结点
{
arr[i]=arr[k];//把较大的值放上去
i=k;//i指向k,继续循环比较
}
else
{
break;
}
}
//当for 循环结束后,我们已经将以i为父结点的树的最大值,放在了最顶部
arr[i]=temp;//将temp的值放到调整后的位置
}
}
学习如逆水行舟,不进则退。和小吴一起加油吧!