代码 -- 堆排序 解决大数组找前K大。

public class Main {

    public static void main(String[] args) {
      //用来模拟的输入数组
        int[] input = new int[]
                {1,6,5,2,7,10,86,21,89,10,87,10,81,3,88,10,123,56,21,
                31,465,31,634,321,564,6987,21,1,1,2,3,5,46,6874,63541,321,321,
                54,32,654,87,365,321,574,687,321,21,653,987,31,321};
        //求前K大
        int K = 10;
        //构建一个数组来存结果
        int[] result = new int[K];
        //将输入的前K个存入数组,并构建小顶堆(二叉堆)
        for(int i = 0;i<K;i++){
            result[i] = input[i];
            int index = i;
            //判断父节点是不是比刚插入的这个节点大,如果大,则调整(交换)。
            while(index != 0 && result[index] < result[getParent(index)]){
                result = swap(result, index, getParent(index));
                index = getParent(index);
            }
        }


        //接下来将input数组中的数字从 下标为K 开始插入堆,如果比堆顶小,则丢弃。
        for(int i = K;i<input.length;i++){
            if(input[i] < result[0])
                continue;
             //用index来存储当前插入进堆中的树的下标。会首先插入在堆顶(原堆顶被遗弃)
            int index = 0;
            result[0] = input[i];
            //如果左子节点存在的话,则开始判断调整,左子节点不存在,有子节点必定不存在。
            while(getLeftSon(result, index)!= -1){
                //用swap来保存应该跟哪个子节点交换,如果为0,则不动,为1,交换左,为2,交换右。
                int swap = 0;
                //如果右子节点不为空,左子节点必定不为空。
                if(getRightSon(result, index)!= -1){
                    //如果当前节点比两个子节点都要大,则与较小的交换。
                    if(result[index] > result[getLeftSon(result, index)] && result[index] > result[getRightSon(result, index)]){
                        if(result[getLeftSon(result, index)] < result[getRightSon(result, index)])
                            swap = 1;
                        else
                            swap = 2;
                    }
                    //如果只比左节点大,则交换左
                    else if(result[index] > result[getLeftSon(result, index)])
                        swap = 1;
                    //如果只比有节点大,交换右
                    else if(result[index] > result[getRightSon(result, index)])
                        swap = 2;
                }
                else{
                    //如果只比左节点大,则交换左
                    if(result[index] > result[getLeftSon(result, index)])
                        swap = 1;
                }
                //进行交换
                switch (swap) {
                case 1:
                    result = swap(result, index, getLeftSon(result, index));
                    index = getLeftSon(result, index);
                    break;
                case 2:
                    result = swap(result, index, getRightSon(result, index));
                    index = getRightSon(result, index);
                    break;
                default:
                    break;
                } 
                if(swap == 0){
                    break;
                }
            }
        }
        for (int i : result) {
            System.out.println(i);
        }
    }
    //获得父亲节点,父亲节点序号为(x - 1)/ 2
    public static int getParent(int x){
        return (int)((x - 1)/2);
    }
    //获得左子节点,序号为2*x + 1,如果不存在,则返回 - 1
    public static int getLeftSon(int[] arr,int x){
        if(2*x + 1< arr.length )
            return 2*x + 1;
        return -1;
    }
    //获得左子节点,序号为2*x + 2,如果不存在,则返回 - 1
    public static int getRightSon(int[] arr,int x){
        if(2*x+2 < arr.length)
            return 2*x + 2;
        return -1;
    }
    //交换
    public static int[] swap(int[] arr, int x, int y) {
        int temp;
        temp = arr[x];
        arr[x] = arr[y];
        arr[y] = temp;
        return arr;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值