常用排序算法(四)堆排序

1.简介

堆排序是利用这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序,

二叉堆满足二个特性:

1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。

2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)

每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。如下图:

同时,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子

该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是:

大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]  

小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]  

2.基本思想

将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了

3.构造初始堆

将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆)

a.假设给定无序序列结构如下

b.此时我们从最后一个非叶子结点开始(叶结点自然不用调整,第一个非叶子结点 arr.length/2-1=5/2-1=1,也就是下面的6结点),从左至右,从下至上进行调整。

c.找到第二个非叶节点4,由于[4,9,8]中9元素最大,4和9交换。

这时,交换导致了子根[4,5,6]结构混乱,继续调整,[4,5,6]中6最大,交换4和6。

此时,我们就将一个无需序列构造成了一个大顶堆。

4.将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换

a.将堆顶元素9和末尾元素4进行交换

b.重新调整结构,使其继续满足堆定义

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

后续过程,继续进行调整,交换,如此反复进行,最终使得整个序列有序

再简单总结下堆排序的基本思路:

  a.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;

  b.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;

  c.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

5.代码实现

def heapSort(list: Array[Int]): Array[Int] = {
    for (i <- list.indices) {
      val len = list.length
      buildMaxHeapTree(list, len - 1 - i)
      //每次loop 后用array(0) 最大值跟最后一个元素互换 ,后面循环时候排序最后一个元素
      swapFunction(list, 0, len - 1 - i)
    }
    list
  }

  def buildMaxHeapTree(array: Array[Int], lastIndex: Int): Unit = {
    //根据最后一个节点计算父节点,最有一个节点可能是左节点 也可能是右节点
    //val parent = (lastIndex -1) / 2
    for (parent <- Range((lastIndex - 1) / 2, -1, -1) if lastIndex > 0) {
      //根据父节点计算左叶子节点
      val leftChild = 2 * parent + 1
      //定义一个变量等于leftchild 索引 ,用于跟父节点做swap 交换
      var swapChild = leftChild
      //根据左边节点计算右边节点
      val rightChild = leftChild + 1
      //判断如果右边节点存在,那么 比较左右几点大小
      if (rightChild <= lastIndex && array(leftChild) < array(rightChild)) {
        swapChild += 1
      }
      //判断父节点跟较大左右节点中的数据大小
      if (array(parent) < array(swapChild)) {
        swapFunction(array, parent, swapChild)
      }
    }
  }

  def swapFunction(array: Array[Int], parent: Int, child: Int): Unit = {
    val temp = array(parent)
    array(parent) = array(child)
    array(child) = temp
  }

  

猜你喜欢

转载自www.cnblogs.com/feiyumo/p/9300198.html