薯薯算法日记01

本文介绍了Java中堆数据结构的使用,包括大根堆的插入、下沉操作,以及堆排序算法的详细步骤。特别关注了如何高效地对近乎有序数组进行排序,以及小根堆在优先队列中的应用。通过实例演示了堆操作技巧及其在特定场景下的优化策略。
摘要由CSDN通过智能技术生成

堆是完全二叉树

i 左 2*i+1 右2*i+2  父(i-1)/2

上浮

//在堆中插入一个数 思路结构  一个一个插入堆时的操作 也可以说是上浮
    public static void heapInsert(int[] arr, int index) {
        while (arr[index] > arr[(index - 1) / 2]) {
            swap(arr, index, (index - 1) / 2);
            index = (index - 1) / 2;
        }

如果比子比父位置大那么子和夫交换 直到子<父

下沉

 

//下沉操作
    public static void heapify(int[] arr, int index, int heapSize) {
        //index从哪个位置开始往下操作 heapSize判断左右两个孩子是否越界
        int left = index * 2 + 1;//左孩子下标
        while (left < heapSize) {
            //下方有孩子  把左右孩子两个孩子大的给largest
            int largest = left + 1 < heapSize && arr[left + 1] > arr[left]
                    ? left + 1 : left;
            //父和较大孩子之间谁的值大 下标给largest
            largest = arr[largest] > arr[index] ? largest : index;

            if (largest == index) {
                break;
            }
            swap(arr, largest, index);
            index = largest;
            left = index * 2 + 1;
        }
    }

index是从何位置往下堆化 heapSize是堆大小 主要用来判断是否越界

首先判断 是否当前位置存在子,如果存在子我们再进行操作 循环操作是 如果存在右子并且右子比左子大那么largest记录右子的下标索引 否则记录左子(此时largest记录的是子中较大那个的索引值) 接下来比较较大子值和索引值哪个更大(此时largest记录的是索引对应值和子值较大的那个)如果此时父值大 那么已经形成大根堆,如果子大那么交换子父的值和索引直到父大为之

如何用堆进行排序

 

public static void heapSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        for (int i = 0; i < arr.length; i++) {
            heapInsert(arr, i);
        }

        for (int i = arr.length - 1; i >= 0; i--) {
            heapify(arr, i, arr.length);
        }

        int heapSize = arr.length;
        swap(arr, 0, --heapSize);
        while (heapSize > 0) {
            heapify(arr, 0, heapSize);
            swap(arr, 0, --heapSize);
        }
    }

 首先把数组搞成大根堆 然后 0位置和最后一个位置交换 然后0位置的数堆化 再交换 依次

当然如果进行大根堆调整 可以从右往左依次让所有子书变成大真堆 再向上变成大根堆 第二个if循环即次

应用 对于一个几乎有序的数组 把数组排好序,每个元素距离不超过k,最好的排序算法是

我们首先让数组的前k+1项变成小根堆 此时 该数组最小的数就应该在0索引 接着我们弹出最小值把后一个值放入小根堆,不断弹出最小值即可

public void sortedArrDistanceLessK(int[]arr,int k){
        PriorityQueue<Integer> heap = new PriorityQueue<>();
        int index = 0;
        for(;index<Math.min(arr.length,k);index++){
            heap.add(arr[index]);
        }
        int i =0;
        for(;index<arr.length;i++,index++){
            heap.add(arr[index]);
            arr[i]=heap.poll();
        }
        while(!heap.isEmpty()){
            arr[i++]=heap.poll();
        }
    }

java中的优先队列底层本质就是一个小根堆,有些情境下必须手写堆,比如需要对堆的内部进行插入操作时。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值