Home

LinkWorld Algorithm Blog

11 Sep 2019

堆排序算法

堆排序算法

基础知识可见:堆排序(大顶堆、小顶堆)—-C语言

思路:(大/小顶堆)先保证父节点大/小于子节点,之后从后往前递归调整位置。

1.第一个过程-调整结点

假如有10个数据,序号的排列如下:

       0
   1       2
 3   4   5   6
7

可以整理出来一层的父子结点关系如下所示:

0 1 2
1 3 4
2 5 6
3 7

从上数据可以看出来,父结点的索引为0、1、2、3、4,可以推导出:

  • 左结点索引为$left\ \ =parent × 2 + 1$
  • 右结点索引为$right=left+1$

2.第二个过程-排序

不断的循环,将当前循环的最大/小值换到数组的最后。

代码实现

Python实现

class HeapSort:

    @staticmethod
    def __endian(arr, start, end, compare_func):
        # 根结点
        root = start
        # 左孩子
        child = root * 2 + 1
        print("start:%s, end:%s, root:%s, left:%s
                -> %s" % (start, end, root, child, arr))
        while child <= end:
            # 判断左右结点的大小,选择其中一个与父结点比较
            if child + 1 <= end and compare_func(arr[child], arr[child + 1]):
                child += 1
            # 与父节点比较
            if compare_func(arr[root], arr[child]):
                arr[root], arr[child] = arr[child], arr[root]
                root = child
                child = root * 2 + 1
            else:
                break

    @staticmethod
    def __big_endian(left_child, right_child):
        return left_child < right_child

    @staticmethod
    def __small_endian(left_child, right_child):
        return left_child > right_child

    @staticmethod
    def __heap_sort(arr, compare_func):
        # 无序区大根堆排序
        first = len(arr) // 2 - 1
        for start in range(first, -1, -1):
            # 从下到上,从左到右对每个节点进行调整,循环得到非叶子节点,调整所有的节点
            HeapSort.__endian(arr, start, len(arr) - 1, compare_func)

        for end in range(len(arr) - 1, 0, -1):
            # 顶部尾部互换位置
            arr[0], arr[end] = arr[end], arr[0]
            # 重新调整子节点的顺序,从顶开始调整
            HeapSort.__endian(arr, 0, end - 1, compare_func)

        return arr

    @staticmethod
    def big_heap_sort(arr):
        return HeapSort.__heap_sort(arr, HeapSort.__big_endian)

    @staticmethod
    def small_heap_sort(arr):
        return HeapSort.__heap_sort(arr, HeapSort.__small_endian)


def main():
    array = [5, 3, 2, 1, 9, 8, 4, 0]
    print("堆排序(大顶堆):%s" % HeapSort.big_heap_sort(array))
    print("堆排序(小顶堆):%s" % HeapSort.small_heap_sort(array))

输出结果

start:3, end:7, root:3, left:7 -> [0, 1, 2, 3, 4, 5, 8, 9]
start:2, end:7, root:2, left:5 -> [0, 1, 2, 9, 4, 5, 8, 3]
start:1, end:7, root:1, left:3 -> [0, 1, 8, 9, 4, 5, 2, 3]
start:0, end:7, root:0, left:1 -> [0, 9, 8, 3, 4, 5, 2, 1]
start:0, end:6, root:0, left:1 -> [1, 4, 8, 3, 0, 5, 2, 9]
start:0, end:5, root:0, left:1 -> [2, 4, 5, 3, 0, 1, 8, 9]
start:0, end:4, root:0, left:1 -> [1, 4, 2, 3, 0, 5, 8, 9]
start:0, end:3, root:0, left:1 -> [0, 3, 2, 1, 4, 5, 8, 9]
start:0, end:2, root:0, left:1 -> [0, 1, 2, 3, 4, 5, 8, 9]
start:0, end:1, root:0, left:1 -> [0, 1, 2, 3, 4, 5, 8, 9]
start:0, end:0, root:0, left:1 -> [0, 1, 2, 3, 4, 5, 8, 9]
堆排序(大顶堆):[0, 1, 2, 3, 4, 5, 8, 9]
start:3, end:7, root:3, left:7 -> [0, 1, 2, 3, 4, 5, 8, 9]
start:2, end:7, root:2, left:5 -> [0, 1, 2, 3, 4, 5, 8, 9]
start:1, end:7, root:1, left:3 -> [0, 1, 2, 3, 4, 5, 8, 9]
start:0, end:7, root:0, left:1 -> [0, 1, 2, 3, 4, 5, 8, 9]
start:0, end:6, root:0, left:1 -> [9, 1, 2, 3, 4, 5, 8, 0]
start:0, end:5, root:0, left:1 -> [8, 3, 2, 9, 4, 5, 1, 0]
start:0, end:4, root:0, left:1 -> [8, 3, 5, 9, 4, 2, 1, 0]
start:0, end:3, root:0, left:1 -> [8, 4, 5, 9, 3, 2, 1, 0]
start:0, end:2, root:0, left:1 -> [9, 8, 5, 4, 3, 2, 1, 0]
start:0, end:1, root:0, left:1 -> [9, 8, 5, 4, 3, 2, 1, 0]
start:0, end:0, root:0, left:1 -> [9, 8, 5, 4, 3, 2, 1, 0]
堆排序(小顶堆):[9, 8, 5, 4, 3, 2, 1, 0]

附录

  • 堆仅仅使用数组,且不使用指针,空间占用小。
  • 时间复杂度:$O(nlog_2n)$
  • 空间复杂度:$O(1)$
  • 稳定性:不稳定

博文

Til next time,
LinkWorld at 22:54

scribble