堆排序:Python实现(中级排序法)

堆排序:Python实现(中级排序法)

在认识堆之前我们先了解一下相关的一些概念:
维基百科(树):
在计算机科学中,树(英语:tree)是一种抽象数据类型(ADT)或是实现这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。它是由n(n>0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
下图就是一个树
在这里插入图片描述
维基百科(二叉树)
在计算机科学中,二叉树(英语:Binary tree)是每个节点最多只有两个分支(即不存在分支度大于2的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒。

  1. 满二叉树:一个二叉树如果每一层的节点数达到最大值
  2. 完全二叉树:叶节点只有最下层和次下层,并且最下面一层的节点都集中在盖层最左边的若干位置的二叉树
    简单地说:完全二叉树是在满二叉树的基础上,最后一行不满但是上面的数必须是从左向右排过来的
    通过下图进一步认识完全二叉树,满二叉树
    在这里插入图片描述
    维基百科(堆):
    堆(英语:Heap)是计算机科学中的一种特别的树状数据结构。若是满足以下特性,即可称为堆:“给定堆中任意节点P和C,若P是C的母节点,那么P的值会小于等于(或大于等于)C的值”。简单点来说对就是一颗完全二叉树
    若母节点的值恒小于等于子节点的值,此堆称为最小堆(min heap)(又称大根堆);
    若母节点的值恒大于等于子节点的值,此堆称为最大堆(max heap)(又称小根堆);
    在堆中最顶端的那一个节点,称作根节点(root node),根节点本身没有母节点(parent node)。
    通过下图了解下大根堆和小根堆:
    在这里插入图片描述
    二叉树的顺序存储方式:
    在这里插入图片描述

通过上图可以发现:
1,父节点索引(i)和左孩子节点索引关系:
0–1 1–3 2–5 3–7 4–9
规律:i–2i+1
2,父节点索引(i)和右孩子节点索引关系:
0–2 1–4 2–6 3–8 4–10
规律:i–2i+2
3,同理,从孩节点(j)找父节点:
规律:j/2-1或者(j-1)//2
4,最后一个拥有孩子的父亲的索引:
规律:(len(li)-1)//2或者len(li)//2-1
堆的排序分为三个步骤:
1,构建堆,即对列表进行一次调整,使得堆顶成为最大堆或者最小堆
2,去掉堆顶,把堆的最后一个元素放到堆顶,通过一次调整使堆有序,此时,堆顶的元素为新堆中的大元素
3,重复步骤2,直到堆变空
现在以列表[9,2,7,3,6,4]为例说明下步骤
1,原始数据:
在这里插入图片描述
2,先从原始数据的7(最后一个含有子节点的父节点)出发,比较,7>4不需要调整,父节点前移到元素2,比较发现右孩子比他大交换,图形如下,父节点继续前移发现不需要交换此时索引移到0,堆的构建完成,构建堆后的数据如图
在这里插入图片描述

3,取出堆顶9,和最后一个元素交换,把最后一个元素放到堆顶,此时最大数9不属堆中的数据,再进行调整堆,堆顶为新堆中的最大元素,整个数据中的第二大元素,重复此过程,直到新堆中只剩下一个元素,具体过程如下图
在这里插入图片描述
在这里插入图片描述
不啰嗦,上代码:

#堆排序
def adjust_heap(li,heap_size,father_index):
    left_child = father_index*2 + 1#通过父节点找左孩子
    right_child = father_index*2 + 2#通过父节点找右孩子
    #无论谁大都使得max_index为最大值的索引
    max_index = father_index
    if left_child <= heap_size and li[left_child] > li[max_index]:
        max_index = left_child
    if right_child <= heap_size and li[right_child] > li[max_index]:
        max_index = right_child
        # max_index不等于father_index说明左孩子或右孩子有比父亲大的数,交换,使父节点所指的数最大
    if max_index !=father_index:
        li[father_index],li[max_index] = li[max_index],li[father_index]
        adjust_heap(li,heap_size,max_index)
def build_heap(li):
    last_father_index = len(li)//2 - 1#找到最后一个含有子节点的父节点的索引
    # 从最后一个拥有子节点的父节点开始,对堆进行调整,把每个子树最大的节点往上移动,知道到达根节点的位置
    for i in range(last_father_index,-1,-1):
        adjust_heap(li,len(li)-1,i)
def sort_heap(li):
    build_heap(li)
    print(f'构建完后的列表是:{li}')
    for i in range(len(li)-1,-1,-1):#选出根节点的数(索引为零)(即为最大值)放在列表的最后
        li[i],li[0] = li[0],li[i]
        adjust_heap(li,i-1,0)#每次取出最大值调整堆
s = input('输入需要排列的数据(数据见用,分隔开):')
l = s.split(',')
li = []
for i in l:
    i = int(i)
    li.append(i)
print(f'排序前的列表是:{li}')
sort_heap(li)
print(f'排序后的列表是:{li}')

以上述例子的运算结果:
在这里插入图片描述
补充:
在Python中有关堆排序的内置模块,代码如下:

import heapq
import random
li = list(range(20))#随机生成一个列表
random.shuffle(li)
print(li)
heapq.heapify(li)#建堆(内置函数建的是小根堆)
l=[]
for i in range(len(li)-1):
    i = heapq.heappop(li)#弹出根节点位置的元素(即最小值)
    l.append(i)
print(l)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值