Swift 堆排序详解

498 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情 。如果哪里写的不对,请大家评论批评。

什么是堆

堆是一种特殊的完全二叉树,他的任何一个节点都大于或者等于他的左右子节点,这种被称为最大堆,可推理根节点是最大的值。如果他的任何一个节点都小于或者等于他的左右子节点,这种被称为最小堆。可推理根节点是最小值。

如图:(红色块是数据的小标)

堆.drawio.png

堆排序

堆排序是利用堆这种数据结构设计的一种算法,经过一系列的建堆,创建最小堆,或者最大堆就可以得到一个有顺序的值。

如图:

堆1.drawio.png

节点的规律

  • 左边的子节点所在位置下标是2*i+1
  • 右边的子节点所在位置下标是2*i+2
  • 两者的父节点所在位置下表是(i-1) / 2

分析

  1. 数据建堆,无序的堆序列
  2. 最大堆:将每个父节点和左右的子节点进行比较,将大的子节点和父节点做交换,直到根节点成为最大的数值,变成最大堆
  3. 最小堆:将每个父节点和左右的子节点进行比较,将小的子节点和父节点做交换,直到根节点成为最小的数值,变成最小堆
  4. 将堆顶的最小值或者最大值和二叉树最后一个节点的值交换,然后提取出最大值或者最小值。数据减少一位
  5. 重复2、3、4的过程,直到只剩下一个堆顶

图解

以上述数据为例【2,3,8,1,4,9,10,7】 下面按照最大堆进行排序

堆2.drawio.png

已经过程就生成了最大堆,按照上述的分析,重复这个过程就可以进行排序,看下图

  1. 首先提出堆顶的最大值与数据最后一位交换,保持最后一位不变化。
  2. 然后依次看下标2的数据为9,其左右子节点分别是2,8保持不变,
  3. 然后看下标为1的数据为7,其左右子节点分别是3,4保持不变,
  4. 最后看下标为0的数据为1,其右子节点数据最大,交换位置,下标0为9,下标2为1,
  5. 这时候还没结束,还要继续比较下标为2的数据与其子节点的数据,发现下标为6的数据大于当前数据,再次进行交换.
  6. 这里我们就得到了另一个最大堆。

(ps):下标为7的数据,存放了我们的最大值,所以不参与比较,在代码中,长度变成了array.count - 1

堆3.drawio.png

此时我们又得到了一个最大堆,提取最大值。又开始了循环,下面不做文字介绍了,看图吧

堆4.drawio.png

堆31.drawio.png

代码Swift

// 堆排序
func adjustHeap(_ array : inout Array<Int>, _ i : Int, _ length : Int){
    // 当前节点,暂定最大数据
    var lar = i
    // 左孩子节点
    let left = i * 2 + 1
    // 右孩子节点
    let right = i * 2 + 2
    
    // 如果左孩子节点存在 && 数据大于当前最大数据 则记录下标数据最大
    if left < length && array[left] > array[lar] {
        lar = left
    }
    // 如果右孩子节点存在 && 数据大于当前最大数据 则记录下标数据最大
    if right < length && array[lar] < array[right] {
        lar = right
    }
    
    // 如果最大数据坐标有变化, 则去替换数据
    if lar != i {
        array.swapAt(lar, i)
        // 替换数据之后,如果当前下标也是父节点,需要继续和子节点比较
        adjustHeap(&array, lar, length)
    }
}

func heapSort(_ array :inout Array<Int>){
    // 建堆
    for i in (0...((array.count - 1) / 2)).reversed() {
        adjustHeap(&array, i, array.count)
    }
    // 排序
    for j in (1...(array.count-1)).reversed() {
        //将堆顶元素与末尾元素进行交换
        array.swapAt(0, j)
        //重新对堆进行调整
        adjustHeap(&array, 0, j)
    }
}
var list : Array<Int> = [2, 3, 8, 1, 4, 9, 10, 7, 16, 14,111,231,51412,3125,12,13]
heapSort(&list)
print(list)

相关链接:

mp.weixin.qq.com/s/6jHYgH-lM…