堆排序

本文深入探讨了堆数据结构的概念,包括大根堆和小根堆的特点,以及如何通过堆插入和堆化操作将数组转换为堆。进一步介绍了堆排序算法的实现过程,包括将数组转换为大根堆,然后通过不断交换和堆化操作进行排序,最终达到O(NlogN)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

堆通常可以理解为树状的数据结构.每个堆都是一棵完全二叉树.在计算机中,堆可以用数组模拟出来.第0个元素作为堆的根,叶子节点的位置为 i * 2 + 1(左叶子) 和 i * 2 + 2(右叶子),i是根节点的index.我们通常把堆分为大根堆和小根堆.

 

大根堆:每棵树以及树内包含的子树,根节点的数值都大于叶子节点的数值.

小根堆则刚好相反,每棵树及树内包含的子树,根节点的数值都小于叶子节点.

 

当随机给我们一个数组,我们可以根据堆生成的规则确认根节点和叶子节点都是哪些,但数组内的数值分布可能既不满足大根堆的分布也不满足小根堆的分布.

 

将一个数组转换成大根堆(HeapInsert)

首先假定数组中的一部分index = 0 ~ index = i 是满足大根堆条件的,最初的时候i = 0,也就是第一个节点本身满足大根堆条件.

i增大1,此时变为0和1是大根堆范围.0是根节点,1是叶子节点.

验证1的值是否大于0位置的值,如果大于,则两个位置数值交换.

如果0位置还有父节点,迭代执行比对和交换的动作

 

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;
    }
}

建立一棵大根堆的复杂度是O(N).

 

Heapify

现有大根堆中,其中一个节点的值变小了.改变之后,以该节点为根节点的子树就不满足大根堆的定义了,将其重新调整为一个大根堆的过程就是Heapify.

 

public static void heapify(int [] arr , int index, int heapSize){
    int left = index * 2 + 1;
    while (left < heapSize){
        //选出左子节点和右子节点之间的最大值
        int largest = (left + 1) < heapSize && arr[left] < arr[left + 1] ? left + 1 : left;
        //子节点最大值同index本身比较选大的,此时的largest是三者比较的最大值
        largest = arr[index] > arr[largest] ? index : largest;
        //三者比较的最大值是index本身,直接break,不需要下沉
        if (largest == index){ break; }
        //如果不满足break条件,下沉.变换坐标.
        swap(arr,largest,index);
        index = largest;
        left = index * 2 + 1;
    }
}

堆排序

1-将要排序的数组变成大根堆(小根堆)

2-将堆的根节点同最后一个叶子节点交换位置

3-堆的范围缩小1,同时执行heapify将变化后的数组重新变为大根堆(小根堆).

4-重复2/3步骤

 

public static void heapSort(int [] arr){
    if (arr.length < 2 && arr == null) { return; }
    for (int i = 0; i < arr.length; i++){
        heapInsert(arr,i);
    }
    int size = arr.length;
    swap(arr,0, --size);
    while (size > 0){
        heapify(arr,0,size);
        swap(arr,0, --size);
    }
}

堆排序的时间复杂度是O(N log N)

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值