zoukankan      html  css  js  c++  java
  • 堆排序

    此堆非彼堆,先简单说一下概念和思路。

    - 是一个完全二叉树
    - 每个非叶子结点都大于或等于其左右子结点的值称为大顶堆
    - 每个非叶子结点都小于或等于其左右子结点的值称为小顶堆
    - 根结点一定是大顶堆中的最大值,一定是小顶堆中的最小值

    构建完全二叉树

    - 待排序数字为 30,20,80,40,50,10,60,70,90
    - 构造一个列表为 [0,30,20,80,40,50,10,60,70,90]

    构建大顶堆

    - 度数为2的结点A,如果它的左右子结点的最大值比它大,将这个最大值和该结点交换
    - 度数为1的结点A,如果它的子节点的值大于它,则交换
    - 如果结点A被交换到新的位置,还需要和其子结点重复上面的过程

    起点的选择

    - 从完全二叉树的最后一个结点的父结点开始
    - 结点数为n,则起始结点的编号为 n//2

    下一个节点选择

    - 从起始结点开始向左找其同层结点,到头后再从上一层的最右边结点开始向左逐个查找,直至根结点

    排序

    - 将大顶堆根结点这个最大值和最后一个叶子结点交换,那么最后一个叶子结点就是最大值,将这个叶子结点排除在待排序结点之外
    - 从根结点开始(新的根结点),重新调整为大顶堆后,重复上一步

    1、堆排序是利用堆性质的一种选择排序,在堆顶选出最大值或者最小值
    2、时间复杂度为O(nlogn)
    3、由于堆排序对原始记录的排序状态并不敏感,因此它无论是最好、最坏时间复杂度均为O(nlogn)
    4、不稳定的排序算法(在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的,否则称为不稳定的)

    import math
    
    # 构建完全二叉树
    origin = [0, 30, 20, 80, 40, 50, 10, 60, 70, 90]
    
    total = len(origin) - 1
    
    # 打印树
    def print_tree(origin, unit_width=2):
        length = len(origin)
        index = 1
        # 由于前面补0了,原本应该是math.ceil(math.log2(len(origin)+1)),这里减一
        depth = math.ceil(math.log2(length))
        sep = ' ' * unit_width
        for i in range(depth-1, -1, -1):    # range(3,-1,-1) [3,2,1,0]
            # 前半部分空格数 7,3,1,0
            pre = 2**i - 1
            print(sep * pre, end='')
            # 偏移量,1,2,4,8
            offset = 2 ** (depth - i - 1)
            # 切片获取数据,origin[1,2],origin[2,4],origin[4,8],origin[8,16]
            line = origin[index: index+offset]
            # 元素间距,0,7,3,1
            intervalspace = sep * (2*pre + 1)
            print(intervalspace.join(map(str, line)))
            index += offset
    
    # 最大堆调整,单个节点调整
    def heap_adjust(total, i, origin):
        """
        total: 节点总数
        i: 当前节点的索引
        """
        #               30
        #       20              80
        #   40      50      10      60
        # 70  90
        while 2*i <= total:
            # 2i为左子节点,2i+1为右子节点
            lchild_index = 2*i
            max_child_index = lchild_index
    
            # total>2i说明还有右子节点
            if total > lchild_index and origin[lchild_index + 1] > origin[lchild_index]:
                max_child_index = lchild_index + 1
    
            # 和子树的根节点比较
            if origin[max_child_index] > origin[i]:
                origin[i], origin[max_child_index] = origin[max_child_index], origin[i]
                i = max_child_index
            else:
                break
    
    # 构建大顶堆
    def max_heap(total, origin):
        # 从i=total//2开始,到堆顶节点,依次调整
        for i in range(total//2, 0, -1):    # range(4,0,-1) [4,3,2,1]
            heap_adjust(total, i, origin)
        return origin
    
    max_heap(total, origin)
    #               90
    #       70              80
    #   40      50      10      60
    # 20  30
    
    # 排序
    def sort(total, origin):
        while total > 1:
            # 堆顶和最后一个节点交换
            origin[1], origin[total] = origin[total], origin[1]
            # 每交换一次就固定一个数
            total -= 1
            if total == 2 and origin[total] >= origin[total - 1]:
                break
            # 这时只有堆顶节点不平衡,调整堆顶节点即可
            heap_adjust(total, 1, origin)
        return origin
    
    print_tree(sort(total, origin))
    #               10
    #       20              30
    #   40      50      60      70
    # 80  90
    

    参考:
    https://zh.wikipedia.org/wiki/堆排序

  • 相关阅读:
    XAML学习笔记之Layout(五)——ViewBox
    XAML学习笔记——Layout(三)
    XAML学习笔记——Layout(二)
    XAML学习笔记——Layout(一)
    从0开始搭建SQL Server 2012 AlwaysOn 第三篇(安装数据,配置AlwaysOn)
    从0开始搭建SQL Server 2012 AlwaysOn 第二篇(配置故障转移集群)
    从0开始搭建SQL Server 2012 AlwaysOn 第一篇(AD域与DNS)
    Sql Server 2012 事务复制遇到的问题及解决方式
    Sql Server 2008R2升级 Sql Server 2012 问题
    第一次ACM
  • 原文地址:https://www.cnblogs.com/keithtt/p/9677781.html
Copyright © 2011-2022 走看看