堆排序

堆排序

堆的特点

  • 堆就是用数组实现的二叉树,并且堆是属于完全二叉树。
  • 堆的父节点的值都比其子节点的值要大(或者小)。
  • 堆分最大堆或者最小堆,最大堆的根节点是整个数组中最大的数。(以此类推最小堆)
  • 知道一节点的下标,可以反推出其父亲节点和两个孩子节点的下标。
  • father = (i-1)/2, leftchild = 2 * i+1,rightchild = 2 * i+2

heapify

当左右子树都是堆时,而因为根节点值导致整个二叉树无法成为堆时,可以通过heapify对改二叉树进行调节,使得改二叉树重新变成堆。

heapify的核心思想是:自上而下进行堆调节,当根节点跟其中一个孩子交换时,不另一个孩子的堆结构。

//交换函数
public static void swap(int[] arr ,int x,int y){
    int tem = arr[x];
    arr[x] = arr[y];
    arr[y] = tem;
}
//其中i是heapify过程开始的下标,n是数组的长度
public static void heapify(int[] arr,int i,int n){
    //假设最大值是根节点i
    int maxindex = i;
    //左孩子:i*2+1
    //右孩子:i*2+2
    int lchild = i*2+1;
    int rchild = i*2+2;
    if (lchild<n && arr[lchild]>arr[maxindex])
        maxindex = lchild;
    if (rchild<n && arr[rchild]>arr[maxindex])
        maxindex = rchild;

    //
    if (maxindex != i) {
        //交换
        swap(arr, i, maxindex);
        //向下递归
        heapify(arr,maxindex,n);
    }
}

创建堆

现实情况下往往,往往很难出现类似于堆的结构的数组,往往是一堆乱序的二叉数组,这时需要通过这个数组重新重构使其变成堆。这时我们需要使用到heapify,通过对二叉数组的最后一个非子节点的节点开始,向上对每个节点进行heapify操作,这样即可获得一个堆。

public static void build_MaxHeap(int[] arr){
        //最后一个子节点下标:arr.length-1
        //最后一个非子节点下标 == 最后一个子节点的父节点:(arr.length-2)/2
        int last_index = (arr.length-2)/2;
        for (int i = last_index; i >= 0; i--)
            heapify(arr,i,arr.length);
    }

堆排序

有了build_MaxHeap和heapify堆排序就变得十分简单了。

public static void HeapSort(int[] arr){
    //先创建堆
    build_MaxHeap(arr);
    
    //堆排序开始
    for (int i = arr.length-1 ; i>0 ; i--){
        //交换堆跟节点和最后一个节点
        swap(arr,0,i);
        //交换后,需要重新heapify一下,将数组重新变成堆
        //因为原堆的根节点(最大值)移动堆最后一位,并从当前堆中脱离出来
        //所以脱离出来一个数值,数组后段有序段就越长
        heapify(arr,0,i);
    }
}

可视堆排序

堆排序可视化网站:https://visualgo.net/zh/heap

posted @   鸭梨的药丸哥  阅读(16)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示