数据结构-堆排序

堆:

完全二叉树(然后联想到树的存储结构---顺序存储(其实就是数组)和链式存储,继续联想到顺序存储结构比较适合完全二叉树和满二叉树,对于一般的二叉树一般采用链式存储结构,对于一般树来说,顺序存储结构的空间利用率太低-----------然后联想到链式存储中的节点结构是----lchild  data   rchild,其中lchild和rchild是指针域----然后联想到n个节点的二叉链表中含有n+1个空指针---利用此空链域组成线索链表。)

所以堆的本质是一种数组对象

重要性质:

任意叶节点小于或者大于它所有的父节点

堆分为大顶堆 和 小顶堆     注意两者对左右孩子的大小关系不做任何要求

堆排序基本思想:

堆排序是一种树形选择排序算法,特点是:在排序过程中,把L[1:n]看成是一颗完全二叉树顺序存储结构,利用完全二叉树中双亲节点和子节点之间的内在关系,在当前无序区中选择最大or最小元素。

堆排序过程

首先将L[1:n]中的n个元素构建初始堆,由于堆本身的特点(比如大顶堆),堆顶元素就是最大值。输出堆顶元素之后吗,通常将堆底元素送入堆顶,此时根节点已经不满足大顶堆的性质,堆被破坏,将堆顶元素向下调整使其继续保持大顶堆的性质,再输出堆顶元素,如此重复,直到堆中元素只剩下一个为止。

构造初始堆:key!

1. 构建初始堆的过程其实就是一个反复筛选的过程。

2. n个节点的完全二叉树,最后一个结点是\left \lfloor n/2 \right \rfloor 个节点(最后一个非叶节点)的孩子。

3. 对第\left \lfloor n/2 \right \rfloor个结点为根的子树筛选(对大根堆来说,若根节点的关键字小于左右节点子女中关键字较大者,则交换),使该子树成堆,之后向前依次对各结点(\left \lfloor n/2 \right \rfloor-1~1)为根的子树进行筛选,看该值是否大于其左右子结点的值,若不是,将左右节点的较大值与之交换,交换后可能还会破坏下一级的堆,于是继续采用上述方法构造下一级的堆,直到以该节点为根的子树构成堆为止。反复利用上述调整堆得方法建堆,直到根节点。

 

代码(有详细解释):

# (向下)调整堆
def adjust_heap(lists, i, size):
# 这里的i其实可能是叶子节点的,所以下面要判断i的左右孩子是否超出了界
# 左孩子
    lchild = 2 * i + 1
# 右孩子
    rchild = 2 * i + 2
# 下面其实就是找最大值的过程(大根堆):先将父节点赋值给最大值,然后用父节点的左右孩子去和max
# 做比较,哪个大就把哪个赋值给max,这里其实隐含了一个左右子节点比较的过程,假如左节点比父节点
# 大,max = lchild,然后将最大值和rchild比较的时候(左右孩子都大于父节点的情况下),相当于
# 左节点和右节点比较,最后max存放的是两个孩子中的最大值。
    max = i
    if i < size/2:
        if lchild < size and lists[lchild] > lists[max]:
            max = lchild
        if rchild < size and lists[rchild] > lists[max]:
            max = rchild
# 假如父节点比左右节点小,则交换父节点和子节点中的最大值
        if max!= i:
            lists[max], lists[i] = list[i], lists[max]
# 因为调整之后可能导致下一级的堆被破坏,所以向下继续调整使其满足堆
#  多说一句,这里的if max != i就说明了父节点一定小于左右节点的较大值,所以可能会破坏下一级的堆
#  如果 if max = i,就不用向下调整了,就继续往前走喽!
            adjust_heap(lists, max, size)

# 构建初始堆
def build_heap(lists, size):
# 只需要从最后一个非叶子节点开始构造就可以,即size/2向上取整的位置。
    for i in range(0, (size/2))[::-1]:
# 调整之后就得到初始堆了,这时候堆顶元素最大or最小,注意,这里的调整过程和之后的调整过程是一样的
            adjust_heap(lists, i, size)

# 堆排序
def heap_sort(lists):
# 获取n,即数组元素的个数
    size = len(lists)
# 构建初始堆
    build_heap(lists, size)
# 从最后一个元素开始循环,堆底和堆顶元素进行交换,交换之后可能会破坏堆,然后就向下调整,使其再次成堆。
    for i in range(0, size)[::-1]:
# 堆顶和堆底交换
        list[0], list[i] = list[i], list[0]
# 调用向下交换的函数,使其满足堆得性质
        adjust_heap(lists, 0, i)

性能分析:

空间:仅仅使用了常数个辅助单元,所以为O(1)

时间:建堆时间为O(n),之后会有n-1次向下操作,每次向下调整所需时间为O(h),h为树高,所已,最坏最好平均时间复杂度都是!!!O(nlogn)

稳定性:不稳定!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值