堆排序
堆排序
堆的特点
- 堆就是用数组实现的二叉树,并且堆是属于完全二叉树。
- 堆的父节点的值都比其子节点的值要大(或者小)。
- 堆分最大堆或者最小堆,最大堆的根节点是整个数组中最大的数。(以此类推最小堆)
- 知道一节点的下标,可以反推出其父亲节点和两个孩子节点的下标。
- 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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)