面试算法突击(一)堆排序

常见的堆排序:先构建大顶堆,每次将大顶与最后一个数替换,重新构建大顶堆。

public class Test {
    public static void main(String[] args) {
        int[] arr={7,2,4,9,3,0,15,11,67,24,99,18,55};

        new Test().heapSort(arr);
        for(int a:arr){
            System.out.println(a);
        }
    }
    public void heapSort(int[] arr){
        int lenth=arr.length;

        /**
     *@TODO:构建大根堆 注意思考为什么是length/2-1,可以考虑节点数为3的时候模拟公式。
        *@return: void
        */
        for(int i=lenth/2-1;i>=0;i--){
            adjustHead(arr,i,lenth);
        }

        /**
        *@TODO:每次将最后一个数和第一个数替换,然后将剩下的数组继续;排成最大堆
        *@return: void
        */
        for(int j=lenth-1;j>=0;j--){
            swap(arr,0,j);

            adjustHead(arr,0,j);
        }
    }
    /**
    *核心代码
    */
    private  void adjustHead(int[] arr,int i,int length){
        int temp=arr[i];
        int child;
        for(child=2*i+1;child<length;child=2*child+1){
            if(child+1<length && arr[child]<arr[child+1]){
                child++;
            }
            if(arr[child]>temp){
                swap(arr,i,child);
             i=child;//思考为什么要替换i
            }
            else {
                break;//思考为什么要用break而不是continue
            }
        }
    }
    private void swap(int[] arr, int i, int j) {
        int temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;    
    }
}

变种题: 查找数组中最大的K个数。

  • 如果要找最大的数,那么就是小顶堆,如果要找最小的数,那就是大顶堆。逻辑关系要理清楚。

  • 寻找最大的K个数,意味着你需要维护一个根节点数目为K的堆。在你构建这么一个堆之后,就要开始进行比较和重构。之所以要构建小顶堆,是为了保证每次比较工作都是最简洁高效的。第K+1个数如果小于堆顶,必然小于堆中其他任意元素,如果大于堆顶,交换元素之后只需要重构最小堆。最终维护的最小堆就是我们所需要的最大的K个数。

import java.util.ArrayList;

 
public class Test10 {
    public static void main(String[] args) {
        int[] arr={1,4,7,3,9,7,8,5,3,6,0};
        System.out.print(new Test10().sortHeap(arr,3));
    }
    public ArrayList<Integer> sortHeap(int[] arr, int k){
        ArrayList<Integer> list=new ArrayList<>();
        int length=arr.length;
        /**
        *@TODO:构建总数为k的小顶堆
        *@return:
        */
        for(int i=k/2-1;i>=0;i--){
            adjustHead(arr,i,k);
        }
        for(int j=k;j<length;j++){
            if(arr[j]>arr[0]){
                swap(arr,j,0);
                adjustHead(arr,0,k);
            }
        }
        for(int i=0;i<k;i++){
            list.add(arr[i]);
        }
        return list;

    }
    /**
     * 核心
     * */
    private void adjustHead(int[] arr,int i,int length){
        int temp=arr[i];
        int child;
        for(child=2*i+1;child<length;child=2*child+1){
            if(child+1<length && arr[child+1]<arr[child]){
                child=child+1;
            }
            if(arr[child]<temp){
                swap(arr,child,i);
                i=child;
            }
            else {
                break;
            }

        }
    }

    private void swap(int[] arr, int child, int i) {
        int temp=arr[i];
        arr[i]=arr[child];
        arr[child]=temp;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值