B站左程云算法视频03

堆是一个完全二叉树结构(包括满二叉树和从左到右变满的二叉树)

二叉树中,对于i节点,左子孩子为2*i+1,右子孩子为2*i+2 父节点为(i-1)/2     用于后续的找

大根堆:完全二叉树里,每一棵子树的最大值是头结点的值

小根堆:每一棵子树的最小值是头结点的值

heapInsert

public static void heapInsert(int[] arr, int index) {
    while(arr[index] > arr[(index-1)/2]) {//与父节点比较,0位置也不成立
        swap(arr, index, (index-1)/2);
        index = (index-1)/2;
    }

}

给定一组数,找出最大值,大根堆的0位置的数;去掉最大值,先设定一个临时变量存最大值,然后把以及形成的堆结构的最后一个位置的数放到0位置上,heapsize-1,然后从头结点开始,与其子节点的最大值进行比较交换,若还有孩子,则继续比较,直到无孩子或不大于则停止

heapify

//某个数在index位置,能否向下移动
public static void heapify(int[] arr, int index, int 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;
    } 
}

给定一个堆,修改i位置数,如果i位置数变大,则往上heapInsert ,变小,往下heapify

完全二叉树的高度o(logN)

heapInsert和heapify o(logN)级别的调整代价

堆排序heapSort

代码:

public static void heapSort(int[] arr){
    if(arr == null || arr.length < 2){
        return ;
    }
    for (int i = 0; i< arr.length; i++){
        heapInsert(arr,i);
    
    }
    int heapSize = arr.length;
    swap(arr, 0 --heapSize);
    while(heapSize > 0){
        heapify(arr, o ,heapSize);
        swap(arr, o ,--heapSize);
    }//把最大值放在刚失效的位置
}

堆排序的时间复杂度o(NlogN) 空间复杂度O(1)

问题:给一组数,怎么变成大根堆

public static void heapSort(int[] arr){
    if(arr == null || arr.length < 2){
        return ;
    }
   
    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, o ,heapSize);
        swap(arr, o ,--heapSize);
    }//把最大值放在刚失效的位置
}

 堆排序扩展题目

堆结构的扩容也是logN级别的,不会影响性能。

Java中现存的堆排序是一个黑盒,不支持已形成的堆结构修改其中一个数,再以小代价形成对结构,所以有时候要自己手写堆结构。

比较器的使用

返回负数的时候,第一个参数放前面;正数的时候,第二个在前面;0无所谓

1)实质上是重载比较运算符

2)比较器可以很好的应用在特殊标准的排序上

3)可以很好的应用在根据特殊标准排序的结构上

比较器可以使用在堆结构里,实现复杂数据的排序。

不基于比较的排序

计数排序

基数排序

//only for no-negative value
public static void radixSort(int[] arr){
    if (arr == null || arr.length < 2){
        return;
    }
    radixSort(arr, 0, arr.length - 1, maxbits(arr));
}

public static int maxbits(int[] arr){
        int max = Integer.MIN_VALUE;
        for(int i = 0; i < arr.length; i++){
            max = Math.max(max, arr[i]);
    }
        int res = 0;
        while(max != 0){
            res++;
            max /= 10;
    }    
    return res;
}

//arr[begin..end]排序
public static void radixSort(int[] arr, int L, int R, int digit){//digit最大值有几个十进制位
        final int radix = 10;
        int i = 0, j = 0;
        //有多少个数准备多少个辅助空间
        int[] bucket = new int[R - L + 1];
        for(int d = 1; d <= digit; d++){//有多少位就进出几次
        //10个空间
        //count[0]当前位(d位)是0的数字有多少个
        //count[1]当前位(d位)是0和1的数字有多少个
        //count[2]当前位(d位)是0、1和2的数字有多少个
        //count[i]当前位(d位)是(0~i)的数字有多少个
        int[] count = new int[radix]; // count[0..9]
        for (i = L; i <= R; i++){
            j=getDigit(arr[i], d);
            count[j]++;
}
        for(i = 1; i < radix; i++){
            count[i] = count[i] + count[i-1];
}
        for(i = R; i >= L; i--){        //倒着看数字放
            j = getDigit(arr[i],d);
            bucket[count[j]-1]=arr[i];
            count[j]--;
}
        for(i = L, j = 0; i <= R; i++, j--){
            arr[i] = bucket[j];
}
}
}

public static int getDigit(int x, int d){
    return (( x / (( int) Math.pow(10, d-1))) % 10);
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值