排序算法专题之堆排序

Posted Python算法之旅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法专题之堆排序相关的知识,希望对你有一定的参考价值。

说在前面  

    普通二叉树是不适合使用线性表来存储的,因为会出现大量的闲置空间,但完全二叉树是个例外使用线性表来存储完全二叉树,不仅不会出现闲置空间,而且还很容易确定孩子结点和双亲结点的位置关系,从而快速对彼此进行定位。

    我们可以根据完全二叉树的这个特点,通过反复构造大根堆,来对数组进行排序,这就是堆排序算法。


“Python算法之旅”微信群等着你
排序算法专题之堆排序
排序算法专题之堆排序
排序算法专题之堆排序
排序算法专题之堆排序

扫码加入“Python算法之旅”微信群,和斌哥面对面交流,更多资料和更有趣的话题等你一起来分享。

排序算法专题之堆排序

堆排序算法(填空版)

1.  完全二叉树

完全二叉树:除了最后一层之外的其他每一层都被完全填充,并且所有结点都保持向左对齐。

 排序算法专题之堆排序

满二叉树:除了叶子结点之外的每一个结点都有两个孩子,每一层都被完全填充。

排序算法专题之堆排序


2.  大根堆和小根堆

堆是一棵顺序存储的完全二叉树。

其中每个结点的关键字都不大于其孩子结点的关键字,这样的堆称为小根堆。

其中每个结点的关键字都不小于其孩子结点的关键字,这样的堆称为大根堆。

 排序算法专题之堆排序


3.  构造大根堆

方法一:通过不断插入新元素,对新元素做向上调整操作,得到新的大根堆。

函数名:create_max_heap(a)

参数表:a -- 待排序列表。

返回值:该方法没有返回值,但是会将列表改造成大根堆。

def create_max_heap_2(a):

    #通过不断插入新元素,对新元素做向上调整操作,将一个普通数组改造成大根堆

    for i in range(2, len(a)+1):

        sift_up(a, len(a), i)


#向上调整二叉堆的第pos个元素a[pos-1],使其满足大根堆的特征

def sift_up(a, n, pos):

    temp = a[pos-1] #第pos个元素的值

    parents = pos // 2 #指向双亲结点

   

    while parents > 0:

        if a[parents-1] < temp: #通过向下移动双亲结点值的方式,确保双亲大于孩子

            a[pos-1] =  ①             

            pos =  ②                  

            parents = pos // 2

        else:

            break

    a[pos-1] = ③                #将temp向上调整到适当位置

   

方法二:通过逆序向下调整非叶子结点,将一个普通数组改造成大根堆。

函数名:create_max_heap(a)

参数表:a -- 待排序列表。

返回值:该方法没有返回值,但是会将列表改造成大根堆。

def create_max_heap(a):

    #通过逆序向下调整非叶子结点,将一个普通数组改造成大根堆

    for i in range(len(a)//2, 0, -1):

        sift_down(a, len(a), i)


#向下调整二叉堆的第pos个元素a[pos-1],使其满足大根堆的特征

def sift_down(a, n, pos):

    temp = a[pos-1] #第pos个元素的值

    child = pos * 2 #指向左孩子a[child-1]

    while child <= n:

        if child < n and a[child-1] < a[child]: #有右孩子,且右孩子更大些,定位其右孩子 

            child += 1 #指向右孩子

        if a[child-1] > temp: #通过向上移动孩子结点值的方式,确保双亲大于孩子 

            a[pos-1] = ①             

            pos = ②                  

            child = pos * 2

        else:

            break

a[pos-1] = ③                #将temp向下调整到适当位置


4.  堆排序

堆排序基本思想:

1.首先将待排序的数组构造成一个大根堆,此时,整个数组的最大值就是堆结构的顶端

2.将顶端的数与末尾的数交换,此时,末尾的数为最大值,剩余待排序数组个数为n-1

3.将剩余的n-1个数再构造成大根堆,再将顶端数与n-1位置的数交换,如此反复执行,便能得到有序数组

函数名:heap_sort(a)

参数表:a -- 待排序列表。

返回值:该方法没有返回值,但是会对列表的对象进行升序排序。

def heap_sort(a):

    create_max_heap(a) #先构造一个大根堆

    for i in range(len(a)-1, 0, -1):

        a[0], a[i] = a[i], a[0]

        sift_down(①                ) #对根结点向下调整,得到长度为i的新大根堆  
堆排序算法(完整版)

3.  构造大根堆

方法一:通过不断插入新元素,对新元素做向上调整操作,得到新的大根堆。

函数名:create_max_heap(a)

参数表:a -- 待排序列表。

返回值:该方法没有返回值,但是会将列表改造成大根堆。

def create_max_heap_2(a):

    #通过不断插入新元素,对新元素做向上调整操作,将一个普通数组改造成大根堆

    for i in range(2, len(a)+1):

        sift_up(a, len(a), i)


#向上调整二叉堆的第pos个元素a[pos-1],使其满足大根堆的特征

def sift_up(a, n, pos):

    temp = a[pos-1] #第pos个元素的值

    parents = pos // 2 #指向双亲结点

   

    while parents > 0:

        if a[parents-1] < temp: #通过向下移动双亲结点值的方式,确保双亲大于孩子

            a[pos-1] = a[parents-1]

            pos = parents

            parents = pos // 2

        else:

            break

    a[pos-1] = temp #将temp向上调整到适当位置

   

方法二:通过逆序向下调整非叶子结点,将一个普通数组改造成大根堆。

函数名:create_max_heap(a)

参数表:a -- 待排序列表。

返回值:该方法没有返回值,但是会将列表改造成大根堆。

def create_max_heap(a):

    #通过逆序向下调整非叶子结点,将一个普通数组改造成大根堆

    for i in range(len(a)//2, 0, -1):

        sift_down(a, len(a), i)


#向下调整二叉堆的第pos个元素a[pos-1],使其满足大根堆的特征

def sift_down(a, n, pos):

    temp = a[pos-1] #第pos个元素的值

    child = pos * 2 #指向左孩子a[child-1]

    while child <= n:

        if child < n and a[child-1] < a[child]: #有右孩子,且右孩子更大些,定位其右孩子 

            child += 1 #指向右孩子

        if a[child-1] > temp: #通过向上移动孩子结点值的方式,确保双亲大于孩子 

            a[pos-1] = a[child-1]

            pos = child

            child = pos * 2

        else:

            break

a[pos-1] = temp #将temp向下调整到适当位置


4.  堆排序

堆排序基本思想:

1.首先将待排序的数组构造成一个大根堆,此时,整个数组的最大值就是堆结构的顶端

2.将顶端的数与末尾的数交换,此时,末尾的数为最大值,剩余待排序数组个数为n-1

3.将剩余的n-1个数再构造成大根堆,再将顶端数与n-1位置的数交换,如此反复执行,便能得到有序数组

函数名:heap_sort(a)

参数表:a -- 待排序列表。

返回值:该方法没有返回值,但是会对列表的对象进行升序排序。

def heap_sort(a):

    create_max_heap(a) #先构造一个大根堆

    for i in range(len(a)-1, 0, -1):

        a[0], a[i] = a[i], a[0]

        sift_down(a, i, 1) #对根结点做向下调整操作,得到长度为i的新大根堆 
写在后面

Python排序算法系列文章是我在阅读了大量算法专著以后,尝试用浅陋的语言把自己的理解表达出来。由于本人水平有限,表述中难免出现疏漏甚至错误之处,敬请谅解。

无论是赞同还是反对我的看法,都请你给我留言。如果你有新的想法,千万不要憋在心里,请发出来大家一起讨论。让我们相互学习,共同进步!


需要本文word版的,可以加入“选考VB算法解析”知识星球参与讨论和下载文件,“选考VB算法解析”知识星球汇集了数量众多的同好,更多有趣的话题在这里讨论,更多有用的资料在这里分享。

我们专注选考VB算法,感兴趣就一起来!



相关优秀文章:




  

以上是关于排序算法专题之堆排序的主要内容,如果未能解决你的问题,请参考以下文章

排序专题-插入排序

排序算法专题之希尔排序

算法排序专题:冒泡排序

排序算法专题之快速排序

排序算法专题之桶排序

排序算法专题之归并排序