排序算法---堆排序

一、堆

堆排序是利用堆这种数据结构来设计的一种排序算法,是一种选择排序(每轮排序会选出一个最大/最小值),最坏、最好、平均时间复杂度均为O(nlogn),是不稳定的排序。

使用堆排序,可以是一个动态的过程,若题目中只需某个排序位的值,则只需排序置该位置,不用全排序好再去拿,只需要针对部分元素进行排序,这样可以降低复杂度。

堆排序过程中,是看不到树的结构的,因为使用完全二叉树的性质,用数组表示对应的树结构,又叫顺序存储。

顺序存储二叉树的特点:

  • 第n个元素父节点为(n-1)/2
  • 第n个元素左子节点为2*n+1
  • 第n个元素右子节点为2*n+2
  • 最后一个非叶子结点为Math.floor(arr.length/2)-1

堆 是具有以下性质的完全二叉树:

  • 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列
  • 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排​

堆排序的基本思想:

1、将待排序序列构造成一个大顶堆(数组)

2、此时整个序列的最大值就是堆顶的根节点

3、将其与末尾元素进行交换,此时尾元素就是最大值

4、再将剩余n-1个元素重新构建成一个堆,这样可以得到n个元素的次最大值。如此反复,可以得到一个有序序列。

二、如何构建堆并排序

下面以数组[3,5,8,6,10]进行堆排序:

步骤一:构造初始堆

1、(操作的为数组)

 将给定无序序列构造成一个大顶堆

2、此时从最后一个非叶子结点开始调整,从左往右,从上往下进行调整

叶节点不做调整,第一个非叶子结点:arr.length/2-1 =5/2-1 = 1,元素5的结点

比较非叶子结点的左右结点,先让6,10比较,得到大的,再和当前结点5作比较,发现10大于5,则交换位置。

 3、找到第二个非叶子结点3,[3,10,8]中,元素10最大,则交换3,10

 4、交换使得子根[3,6,5]结构排乱,所以再对其进行调整,[3,6,5]中6最大,将3,6位置进行调换

 于是便将一个无序序列构建成为一个大顶堆

步骤二:将堆顶元素与末尾元素进行交换

将堆顶元素与末尾元素进行交换,交换后使末尾元素变为最大。再继续上述步骤,得到第二大元素,如此反复交换便可完成排序堆的构造。

1、将堆顶元素10与末尾元素交换

  2、重新调整结构,使其满足堆定义

 3、再将堆顶元素8与末尾元素3进行交换,得到第二大元素8

 4、如此反复,最终使得整个序列有序

三、总结:

1、将无序序列构建成一个堆,根据升序降序决定是大顶堆还是小顶堆

2、将堆顶元素与末尾元素交换,将最大元素“沉”到数组末端

3、重新调整结构,使其满足堆定义,然后继续交换堆顶与当前末尾元素,如此反复,直至整个序列有序

四、代码

var Heap = function(nums) {
   let heapSize=nums.length
    buildMaxHeap(nums,heapSize) // 构建好了一个大顶堆
    // 进行下沉 大顶堆是最大元素下沉到末尾
    for(let i=nums.length-1;i>=0;i--){
        swap(nums,0,i)
        --heapSize // 下沉后的元素不参与到大顶堆的调整
        // 重新调整大顶堆
         maxHeapify(nums, 0, heapSize);
    }
    console.log(nums)
   // 自下而上构建一颗大顶堆
   function buildMaxHeap(nums,heapSize){
     for(let i=Math.floor(heapSize/2)-1;i>=0;i--){
        maxHeapify(nums,i,heapSize)
     }
   }
   // 从左向右,自上而下的调整节点
   function maxHeapify(nums,i,heapSize){
       let l=i*2+1
       let r=i*2+2
       let largest=i
       if(l < heapSize && nums[l] > nums[largest]){
           largest=l
       }
       if(r < heapSize && nums[r] > nums[largest]){
           largest=r
       }
       if(largest!==i){
           swap(nums,i,largest) // 进行节点调整
           // 继续调整下面的非叶子节点
           maxHeapify(nums,largest,heapSize)
       }
   }
   function swap(a,  i,  j){
        let temp = a[i];
        a[i] = a[j];
        a[j] = temp;
   }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值