堆排序相关知识总结

相关连接:

堆排序图解


参考代码:

public static void heapSort(int[] nums){
   int len = nums.length;
   //1.建最大堆:从下到上,从左到右
   for(int i = len / 2 - 1; i >= 0; i--){
       heapify(nums, i, len);
   }
   //2.每次调整第0个元素和 “最后一个元素” 的位置
   for (int i = len - 1; i > 0; i--) {
       swap(nums, 0, i);//将第0个元素和 “最后一个元素” 的位置进行交换
       heapify(nums, 0, i);//交换后重新从第0个元素开始将剩下的元素调整为最大堆
   }
}
public static void heapify(int[] nums, int i, int n){
   int l = i * 2 + 1;//左孩子索引
   int r = i * 2 + 2;//右孩子索引
   int maxIndex = i;
   if(l < n && nums[l] > nums[maxIndex])maxIndex = l;
   if(r < n && nums[r] > nums[maxIndex])maxIndex = r;
   if(maxIndex != i){//说明子节点中有比根节点大的值,要交换
       swap(nums, maxIndex, i);//交换
       heapify(nums, maxIndex, n);//交换后将以第maxIndex个结点为根节点的结点调整为最大堆
   }
}
public static void swap(int[] nums, int i, int j){
   int temp = nums[i];
   nums[i] = nums[j];
   nums[j] = temp;
}

相关说明:

1.随机的数组其实可以当成一个堆,所以直接在数组(堆)上进行操作就行。

2.升序,一般将堆转化为最大堆,降序,一般将堆转化为最小堆。

3.从下到上,从右到左,找到第一个非叶子结点开始进行转化。

4.转化时,如果左右孩子的值都不比结点大,不用调整,跳过,转化下一个结点;否则,将父节点值和子节点值中较大的进行交换,然后将进行交换的子节点重新转化为最大堆,这里注意:重新转化时是从上到下转化,因为此时只有该子节点有可能比他的子节点小,而该子节点的子节点肯定符合最大堆,不用从下到上进行调整。

5.进行最大堆调整时,从第len / 2 - 1个结点从后到前进行调整,一直调整到第0个结点。

6.转化完成后,开始排序:
将根节点的最大元素和第len - 1个元素进行交换,交换后根元素不符合最大堆,而他的子元素符合最大堆,所以从上到下转换为最大堆。注意是对剩下的len - 1个元素进行调整(对应关系)。
从将根节点的最大元素和第len - 2个元素进行交换,交换后根元素不符合最大堆,而他的子元素符合最大堆,所以从上到下转换为最大堆。注意是对剩下的len - 2个元素进行调整(对应关系)。

最后只剩下一个索引为0的元素,也为最小的元素,不用进行排序,所以循环len - 1次。

7.索引为i的元素,左孩子索引为2 * i + 1,右孩子索引为2 * i + 2;

8.时空复杂度:建堆O(N);排序O(logN),时间复杂度O(NlogN)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值