排序算法-堆排序

堆排序

算法描述

堆排序算法具有空间原址性,(二叉)堆是一个数组,它近似完全二叉树,树上的每一个节点对应数组中的一个元素,除了最底层外,该树是>完满的,而且从左向右填充。

最大堆性质

最大堆指的是对于某个节点,其值一定不小于其左右子节点的值,不大于其父节点的值: Arr[PARENT(i)]>=ARR[i]。

算法思想

首先,利用最大堆性质,将序列建成最大堆,因为数组中最大元素总在根节点Arr[1]中,通过把它与Arr[n]进行交换,然后将最后的节点从堆中去掉,新根节点可能会违背最大堆性质,因此对剩余节点进行调整以维护最大堆性质。因此算法步骤为:

  • 建立最大堆
  • 循环:
    • 交换堆中第一个元素与最后一个元素
    • 去除堆中最后一个节点
    • 维护最大堆性质

伪代码为:

  • HEAPOSORT(A)
    1. BUILD-MAX-HEAP(A)
    2. for i =A.length downto 2
    3.    exchange A[1] with A[i]
    4.    A.heap-size=A.heap-size-1
    5.    MAX-HEAPIFY(A,1)

算法实现(python)

 #-*- coding:utf-8 -*-

heap_size=0
b=[-1]
def parent(i):  #求父节点的下标
    return int(i/2)

def left(i):    #求左孩子的下标
    return 2*i
def right(i):   #求右孩子的下标
    return 2*i+1
def add(a):
    for i in a:
        b.append(i)

def maxHeapify(a,i):    #维持最大堆的性质
    l=left(i)
    r=right(i)
    if (l<=heap_size) and (a[l]<a[i]):
# and相当于java中的&&,会以“短路”的方式判断。从左到右计算表达式,若所有值均为真,则返回最后一个值,若存在假,返回第一个假值。
# or也是从左到有计算表达式,返回第一个为真的值,相当于java中的||
        largst=l
    else:largst=i
    if (r<=heap_size)and (a[r]<a[largst]):
        largst=r
    if (largst!=i):
        t=a[i]
        a[i]=a[largst]
        a[largst]=t
        maxHeapify(a, largst)    

def buildMaxHeap():     #建立最大堆
    #reversed会将列表元素反向排列并且返回,list.reverse()方法只讲列表反向排序不返回值。
    for i in list(reversed(range(1,int(heap_size/2)+1))):
        maxHeapify(b, i)

def heapSort(a):      #堆排序算法,是一种原址排序法
    add(a)
    global heap_size,b   #在方法中修改全局变量的值时要加global关键字,否则直接赋值会创建相同名字的局部变量,并覆盖全局变量的值。
    heap_size=len(b)-1
    buildMaxHeap()
    for i in list(reversed(range(1,len(b)))):
        t=b[1]
        b[1]=b[i]
        b[i]=t
        heap_size=heap_size-1
        maxHeapify(b, 1)
    del b[0] #del 可以按索引删除列表中元素,list.remove(obj)按元素删除
    return b

if __name__ =="__main__":
    a=[2,4,3,9,7,5,77,5,12,5]
    print heapSort(a)

算法复杂度

维护最大堆:时间复杂度为O(logn)
建立最大堆:线性时间复杂度
堆排序:时间复杂度为O(n*logn)


参考

《算法导论》第三版

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值