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

    堆的相关知识:


    堆?
    1.堆是一种完全二叉树
    2.每个节点的值总是大于等于(大根堆)或者小于等于(小根堆)子节点的值.

    完全二叉树?
    除了最后一层外, 每一层都被完全填充, 且所有节点都向左对齐.

    大根堆:
    每个节点都大于等于子节点
    小根堆:
    每个节点都小于等于子节点


    堆排序需要使用两个函数. 实现以下功能
    1. 构建堆,以及实现堆内部对比以及调换.
    2. 堆排序的调用, 以及堆大小的控制

    # 堆排序_Python实现
    # 堆最大化
    def heapify(li, i, n):
        # 父节点位置n
        largest = i
        # 子节点位置,左,右
        left = i * 2 + 1
        right = i * 2 + 2
        if left < n and li[left] > li[largest]:
            largest = left
        if right < n and li[right] > li[largest]:
            largest = right
        if largest != i:
            li[largest], li[i] = li[i], li[largest]
    
            # 显示变动
            # print(li)
    
            # 当位置发生变动的时候, 递归调用, 重新排位
            heapify(li, largest, n)
        # 因为是直接针对list列表内进行排序, 则不需要返回列表
    
    
    # 堆排序
    def heap_sort(li):
        n = len(li)
    
        # 自下至上建堆
        for i in range(n // 2 - 1, -1, -1):
            heapify(li, i, n)
        for i in range(n - 1, -1, -1):
            li[0], li[i] = li[i], li[0]  # 该循环中,i有两个含义:1.代表当前堆中最后一个节点的下标(转化后为最大值).2.代表下次循环中堆的大小(相当于省却n-1步骤.)
                                         # 这样, 在进行堆计算的时候, 就把已经调换至最后一个的最大值忽略掉, 直接进行下次排序.
            heapify(li, 0, i)  # 在传入下标的时候, 只需要传入0, 也就是从堆最后交换过来的元素(因为上次排序好之后只有该元素不符合顺序).然后交给heapify来重新梳理即可.
        return li
    
    
    list = [1, 55, 98984, 65, 165, 356, 54, 3, 645, 74, 64, 35]
    list = heap_sort(list)
    
    print(list)
    

      

      

    堆结构特点:

    任何一排的元素数量,等于上面元素总和+1.


    注意点:
    在构建堆的时候,因为需要反顺序, range的时候需要写入步长-1
    在写堆排序的时候, 最需要注意的点, 在于主节点下标的数值, 以及堆大小.
    逻辑流程:
    在构建堆的时候, 从最底部的父节点开始,这样可以一次构建成功,多次向下转换.
    根据堆的特点, 计算出, 我们的最后一个父节点应该是n//2-1. 此处应使用整除,避免浮点.
    在堆化逻辑内
    每个父子节点都会比较大小. 一旦子节点大于父节点,则交换.
    且, 交换下去的节点,重新与它下面的子节点对比,如果它仍然比现在位置的子节点小, 继续交换.
    直到无法交换为止. 这个过程完成了堆的排序.
    构建完成后, 当前堆的第一个元素一定是列表中最大的.
    在后面调用堆排序的时候, 一般通过交换第一个和最后一个元素,来把最大元素保留在列表最后.
    并且使堆大小-1, 这样交换过去的最大值元素就不在计算在堆内.
    而新交换过来的元素此时为首位元素. 这个时候对首位以及它的子节点进行堆化整理, 能够重新使堆变得整齐起来. (这元素比子节点小,往下挪,挪了之后还小?继续往下挪! ...)
    这样, 重新堆化过后的首位元素, 依旧是堆内所有元素中最大的.
    那么, 继续~
    交换头尾, 堆大小减一, 重新排序..
    交换头尾, 堆大小减一, 重新排序...

  • 相关阅读:
    js:值类型/引用类型/内存回收/函数传值
    JS学习计划
    起点
    哈夫曼压缩/解压缩(控制台,C++)
    二维数组作为函数参数传递(C++)
    二级指针和指针引用函数传参(C++)
    学生管理系统(C++,控制台,文件读取,姓名排序)
    C++的getline()和get()函数
    二叉排序树节点的删除(C++,算法导论),前中后序遍历(递归/非递归,栈实现),按层次遍历(队列实现)
    QT程序打包成EXE
  • 原文地址:https://www.cnblogs.com/jrri/p/12099946.html
Copyright © 2011-2022 走看看