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