排序(一)堆排序

参考:https://www.bilibili.com/video/BV1Eb41147dK

堆的定义/条件:如果一颗完全二叉树,且满足parent ≥ children,称为大顶堆;或者parent ≤ children,称为小顶堆。
完全二叉树:逐层从上向下从左至右添加节点。
注:下面的算法只讨论大顶堆。

一、一颗完全二叉树如何构建成一个大顶堆?
用一个一维数组表示一棵完全二叉树,中间无断开,且可以拿到一个节点的父子节点的索引下标。
根据完全二叉树的性质:对于索引下标,parent = (i-1) / 2 ;c1 = 2i + 1; c2 = 2i + 2。除法取整。
从最后一个父节点开始从后向前对所有父节点做heapify操作,也即从后向前对所有的父节点做heapify。 (从最后一个父节点开始,最后一个父节点索引 = (最后一个子节点-1)/ 2

heapify操作 - 确保当前节点下面的分支是堆结构:
先在三个节点中取最大值,把最大值换到父节点上。
然后如果最大值所在节点不是原来根节点,交换之后,仍需对原最大值所在节点做一次heapify(递归)。

二、堆如何进行排序?
根节点肯定一定是最大的节点,
首先交换根节点与最后一个节点,把最后一个节点拎出来(相当于从树中删除最后一个节点,存到数组的最后一个位置);
然后对于新的根节点再做一次heapify(而不用做build_heap,因为除了根节点,其他分支都是大顶堆结构),使根节点仍然是当前堆得最大值,维持一个堆结构;
然后重复上述过程,直到剩下最后一个节点:根节点与最后一个节点交换,把最后一个节点拎出来,再做一次heapify。

三、代码实现:
堆排序:先建堆,再执行堆排序的过程。

 	public static void swap(int arr[],int i, int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    // 功能:对第i个节点做heapify。参数:arr二叉树数组,n二叉树长度,i为当前节点。
    public static void heapify(int arr[],int n,int i){
        if(i >= n) return;
        int max = i;
        int child1 = 2*i+1;
        int child2 = 2*i+2;
        if(child1 <n && arr[max] < arr[child1]) max = child1;
        if(child2 <n && arr[max] < arr[child2]) max = child2;
        if(max != i){
            swap(arr,i,max);
            // 对上一轮max所在索引处做heapify
            heapify(arr,n,max);
        }
    }
    // 功能:将一颗完全二叉树构建成一个大顶堆
    public static void build_heap(int arr[], int n){
        int last_node = n-1;
        //最后一个父节点索引
        int parent = (last_node - 1) / 2;
        //从后向前对所有的父节点做heapify
        for(int i = parent; i >= 0; i--){
            heapify(arr,n,i);
        }
    }
    // 功能:给一个大顶堆排序
    public static void sort_heap(int arr[], int n){
        for(int i = n-1;i > 0;i--){
            //交换最后一个节点和第一个节点
            swap(arr,i,0);
            // 对第一个节点做heapify,确保堆结构,执行heapify操作的数组长度为i,
            // 即最后一个节点不参与heapify,意味着把最后一个节点去掉
            heapify(arr,i,0);
        }
    }
    public static void main(String args[]){
        int[] arr = {4,7,9,1,3,3,5,2};
        int n = 8;
        build_heap(arr,n);
        sort_heap(arr,n);
        for(int i:arr){
            System.out.println(i);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值