用数组实现堆排序的代码Java版

首先要知道,堆其实就是完全二叉树。所谓完全二叉树,可以理解为,在满二叉树的基础上,可以缺少一些结点,缺少的节点只能从满二叉树的右下角开始缺少。也就相当于从从左到右从上到下开始构建的一棵二叉树,节点只能这样排列,不能跳。
那么,根据完全二叉树的特点,父节点的左孩子left=父节点 x 2+1,右孩子right=父节点 x 2+2,父节点=(孩子节点-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;
        }
    }
private static void swap(int[] arr,int l1,int l2) {
        int temp=arr[l1];
        arr[l1]=arr[l2];
        arr[l2]=temp;
    }

当堆中某个元素变小时,就需要向下调整堆,此时,依次和两个孩子节点比较,如果孩子节点更大,就交换,然后孩子再和孩子节点比较,直到比两个孩子都大或者到叶子节点为止。
代码:

public static void heapify(int[] arr,int index,int size){
        int left=index*2+1;
        int right=left+1;
        while (left<size){
            int large;
            if(right==size){
                large=left;
            }else {
                large=arr[left]>arr[right] ? left : right;
            }
            if(arr[index]<arr[large]){
                swap(arr,index,large);
                left=large*2+1;
                right=left+1;
                index=large;
            }else {
                return;
            }
        }
    }

private static void swap(int[] arr,int l1,int l2) {
        int temp=arr[l1];
        arr[l1]=arr[l2];
        arr[l2]=temp;
    }

上面两步其实都是为堆排序打基础的,所谓堆排序:
一、构建大根堆
二、把最后一位和数组第一位交换,因为原本数组第一位就是大根堆的根节点,因此,此时最大值变成数组最后一位。
三、此时,原本的根节点改变了,变小了,就是上面第二步代码的情景,然后此时再依次向下调整堆,使堆再次成为大根堆,注意,这一步需要排除掉刚才交换到最后一位的最大值。 此时大根堆的范围往前缩小一位。
四、循环上面的步骤,大根堆依次缩小,直到大根堆剩一个数,此时堆排序完成。

完整的堆排序代码:

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--) {
            swap(arr,0,i);
            heapify(arr,0,i);
        }
    }

    //构建大根堆
    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 size){
        int left=index*2+1;
        int right=left+1;
        while (left<size){
            int large;
            if(right==size){
                large=left;
            }else {
                large=arr[left]>arr[right] ? left : right;
            }
            if(arr[index]<arr[large]){
                swap(arr,index,large);
                left=large*2+1;
                right=left+1;
                index=large;
            }else {
                return;
            }
        }
    }
    
    //交换
    private static void swap(int[] arr,int l1,int l2) {
        int temp=arr[l1];
        arr[l1]=arr[l2];
        arr[l2]=temp;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值