堆排序:
1.先创建好大根堆
2.每一趟将堆顶元素加入有序子序列【即将堆顶元素与待排序序列中的最后一个元素交换】
3.将待排序元素序列再次调整为大根堆
图解:
书上代码是从i=1存储元素,相当于在i=4(i=len/2)时调整 |
---|
下处代码是从i=0存储元素,所以在i=3(i=len/2-1)时调整 |
public class 堆排序 {
public static void main(String[] args) {
// int nums[]={1,3,4,5,2};
int nums[]={49,38,65,97,76,13,27,49,55,04};
sort(nums);
System.out.println(Arrays.toString(nums));
}
static void sort(int nums[]){
int len = nums.length;
BuildMaxHeap(nums); //建立初始堆
for (int i=len-1;i>0;i--){
swap(nums,i,0); //将堆顶元素输出(和堆底元素交换)
HeadAdjust(nums,0,i); //重新调整为新堆
}
}
//建立大根堆
static void BuildMaxHeap(int nums[]){
int len = nums.length;
for(int i=len/2-1;i>=0;i--){
HeadAdjust(nums,i,nums.length); //反复调整堆,使其成为大根堆
}
}
static void HeadAdjust(int[] nums, int k, int len) {
int temp=nums[k]; //暂存子树的根节点
//i=i*2+1找到 所调整结点的左子树
//i=i*2+1是确保调整后的 “子树” 也能保持大根堆状态
//如果调整后,“调整结点所在子树” 不能保证大根堆,i=i*2+1发挥作用,重新调整子树
for (int i =2*k+1;i<len;i=i*2+1){
if (i+1<len&&nums[i]<nums[i+1]) //比较孩子结点
i++; //取key较大的子结点的下标
if (temp>=nums[i]) break; //筛选结束
else{
nums[k]=nums[i]; //将nums[i]调整到双亲结点上
k=i; //修改key值,以便能够继续向下筛选
}
}
nums[k]=temp; //被筛选结点的值放入最终位置
}
static void swap(int nums[],int a,int b){
int temp = nums[a];
nums[a]=nums[b];
nums[b]=temp;
}
}