堆排序的奇淫技巧

堆排序

    首先了解一下什么是堆排序?
    堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。其复杂度为0(nlogn),有两种形式:
大顶堆:
在这里插入图片描述
小顶堆:
在这里插入图片描述
    如图所示,大顶堆的父节点要比其左右两个子节点的值都要大;同理,小顶堆的父节点要比其左右两个子节点的值都要小。
    不论是大顶堆还是小顶堆,其左右(孩子)节点都是2i+1(左)、2i+2(右),其中i表示父节点的下标。

算法思路:

     将无序数组进行堆化,构建小顶堆或大顶堆(一般升序采用大顶堆,降序采用小顶堆)。从第一个非叶子节点开始(叶结点自然不用调整,第一个非叶子结点 n/2-1,n是数组长度)分别比较该父节点的左右节点,若该父节点小于子节点则进行交换,交换后的子节点数值发生变化可能会不满足堆的性质,需重新调整二叉树的结构
     初始堆完成以后,将根节点与最后一个节点交换(以大顶堆为例)交换后,此时最后一个元素为最大的值,不满足大顶堆的性质,对其进行向下调整,重新调整为大顶堆的形式,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换。
    简单来说就三个步骤:

  • 对无序数组进行初始堆化
  • 将根节点与最后一个节点交换,将最大元素“沉”到末端
  • 重新调整堆的结构,然后将根节点与倒数第二个节点交换,将第二大元素“沉”到末端,以此类推重复上述过程,将堆变成有序即可。
         话不多说,上代码: (温馨提示,没写主方法,需要自己调用测试
 static void sort(int[]nums){
	  Int  n=nums.length;
      //对数组进行堆化
	  Maxheap(nums,n);
      //把最后一个元素和堆顶进行对调
      int i;
      for (i = n-1; i >=0; i--) {
         swap(nums,0,i);
           //缩小堆的范围对堆顶进行向下调整
         MaxheapFixedDown(nums,0,i);
      }
   }
   static void swap(int[]nums,int p,int r){
     int temp=nums[p];
     nums[p]=nums[r];
     nums[r]=temp;
  }

   

若将数组化为大顶堆:(升序)

  static void Maxheap(int[]nums){
	  Int n = nums.length;
      for (int i = n/2-1; i >=0; i--) {
         MaxheapFixedDown(nums,i,n);
      }
   }
   static void MaxheapFixedDown(int[]nums,int i,int n){
      //找到父节点的左右两个孩子
      int left=2*i+1;
      int right=2*i+2;
      //比较孩子大小,如果父节点最大则不用交换
      if(left>=n){
         return;
      }
      int max=left;
      if(right>=n){
         max=left;
      }else if(nums[left]<=nums[right]){
         max=right;
      }
      if(nums[i]>=nums[max])return;
      //否则将两个孩子中最大的与父元素交换
      swap(nums,i,max);
      //重新调整二叉树的顺序,变成大顶堆(顺序)
      MaxheapFixedDown(nums,max,n);
   }

若将数组化为小顶堆:(降序)

static void Minheap(int[]nums){
      int n=nums.length;
      for (int i = n/2-1; i >=0; i--) {
         MinheapFixedDown(nums,i,n);
      }
   }
   static void MinheapFixedDown(int[]nums,int i,int n){
      //找到父节点的左右两个孩子
      int left=2*i+1;
      int right=2*i+2;
      //比较孩子大小,如果父节点最小则不用交换
      if(left>=n){
         return;
      }
      int min=left;
      if(right>=n){
         min=left;
      }else if(nums[left]>=nums[right]){
         min=right;
      }
      if(nums[i]<=nums[min])return;
      //否则将两个孩子中最小的与父元素交换
      swap(nums,i,min);
      //min的位置发生改变,重新调整二叉树的顺序,变成小顶堆(逆序)
      MinheapFixedDown(nums,min,n);
   }

     so easy too happy!👀

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值