241017-堆排序

50 阅读1分钟

image.png

image.png

大根堆化:从非叶子节点开始从右到左从下到上下沉。因为每个节点的子节点都是大根堆化的,所以最终单个节点下沉后的树也必然是大根堆,故先保证子树是大根堆

//学习堆排序:
//首先大根堆化,然后遍历替换头部和末尾元素,此时末位确定
public int[] sortArray(int[] nums) {
    heapify(nums);
    for (int i = nums.length - 1; i >= 0; i--) {
        swap(nums, 0,  i);
        //不要涉及已经排序的位置
        swiftDown(0, nums, i);
    }
    return nums;
}

public void heapify(int[] nums){
    //每个非叶子节点开始下沉,因为叶子节点不需要下沉
    for (int i = (nums.length / 2 - 1); i>=0; i--) {
        swiftDown(i, nums, nums.length);
    }
}

public void swiftDown(int pos, int[] nums, int length){
    //如果不符合大根堆,就继续下沉
    while ((pos * 2 + 1) <= length - 1){
        int left = pos * 2 + 1;
        int right = left + 1;
        int tmp;
        if (right <= length - 1 && nums[right] > nums[left]){
            tmp = right;
        }else{
            tmp = left;
        }

        if (nums[tmp] > nums[pos]){
            swap(nums, tmp, pos);
            pos = tmp;
        }else {
            return;
        }
    }
}


public void swap(int[] nums, int i ,int j){
    int tmp = nums[i];
    nums[i] = nums[j];
    nums[j] = tmp;
}