Python 算法 实现堆排序

本文详细介绍了堆排序算法,包括最大堆和最小堆的概念,堆排序的步骤,以及如何利用堆实现优先队列。堆排序结合了归并排序和插入排序的优点,具有空间原址性。文中提供了Python代码实现,包括堆排序算法、构建最大堆、维护最大堆性质、优先队列的操作如插入、提取最大值等。最后,展示了利用这些函数操作序列的示例。
摘要由CSDN通过智能技术生成

堆排序

参考书《算法导论》
排序是算法中最为基础的问题,这篇文章是关于堆排序算法的理论和python实现

堆排序

在算法导论(一)中有两种排序方法,分别是归并排序和插入排序。其中归并排序有较好的渐近运行时间,而插入排序有空间原址性。堆排序综合了这两种排序的优点。

空间原址性
空间原址性是指,假设对一个序列进行排序,保存在序列外的数是常数级的,就称其具有空间原址性。

1 堆(heap)

堆是一种特殊的数据结构。一般下常常看作二叉树的数组对象,此时也叫二叉堆。
堆的结构有如下一些性质:

  • 父节点的下标是i时,左子节点下标为2i,右子节点为2i+1
  • 子节点序下标是i时,父节点等于[ i/2 ]向下取整

二叉堆可以分为两种形式:

  • 最大堆
    • 要求:任意子节点都不大于父节点
  • 最小堆
    • 要求:任意子节点都不小于父节点

在堆排序中使用最大堆,最小堆常常用于优先队列的构造。

数据结构
将若干数据以某种方式进行组织的方法。

2 堆排序算法

通过函数max-heapify来维护最大堆的性质。这个函数的时间复杂度是 l g ( n ) lg(n) lg(n)

python实现

def max_heapify(A,i,heap_size):
    l=i<<1           #好的实现应该要用宏或内联函数 #左移1位乘2
    r=l+1
    if l<=heap_size and A[l-1]>A[i-1]:
        largest=l
    else: largest=i

    if r<=heap_size and A[r-1]>A[largest-1]:
        largest=r

    if largest!=i:
        A[i-1],A[largest-1]=A[largest-1],A[i-1]
        max_heapify(A,largest,heap_size)   #递归调用

利用这个函数可以维护最大堆父节点比子节点大的性质。

然后利用max_heapity可以写出从一个序列构建最大堆的函数

python实现

def build_max_heap(A):
    heap_size=len(A)
    P=A[:]
    for i in range(int(heap_size/2),0,-1):
        max_heapify(P,i,heap_size)
    return P

利用最大堆实现排序算法,因为每次最大堆的根节点,一定是当前序列中最大的数,所以每次从根节点取出数来,然后在维护最大堆性质,再取,就可以把所有数排完。

def heapsort(A):
    P=build_max_heap(A)
    heap_size=len(P)
    for i in range(len(P),0,-1):
        P[0],P[i-1]=P[i-1],P[0]
        heap_size=heap_size-1     #每取出一个数,heap大小减1
        max_heapify(P,1,heap_size)
    return P

打印结果

print(v)
print(build_max_heap(v))
print(heapsort(v))

[84, 61, 82, 61, 48, 62, 35, 18, 14, 92]
[92, 84, 82, 61, 61, 62, 35, 18, 14, 48]
[14, 18, 35, 48, 61, 61, 62, 82, 84, 92]

3 利用堆实现优先队列

优先队列是一种用来维护由一组元素构成的集合S的数据结构,其中每个元素都有一个相关值,称为关键字。可以分为最大优先队列和最小优先队列,这里讨论最大优先队列。
队列支持以下操作:

  • insert(S,x):把x插入到集合S中
  • maximum(S):返回S中最大键字的元素
  • extract_max(S):去掉并返回S中具有最大键字的元素
  • increase-key(S,x,k):将元素x的关键字值增加到k,假设k不小于x的原关键字

python 实现

def max_heapify(A,i,heap_size):
    l=i<<1           #好的实现应该要用宏或内联函数 
    r=l+1
    if l<=heap_size and A[l-1]>A[i-1]:
        largest=l
    else: largest=i

    if r<=heap_size and A[r-1]>A[largest-1]:
        largest=r

    if largest!=i:
        A[i-1],A[largest-1]=A[largest-1],A[i-1]
        max_heapify(A,largest,heap_size)   #递归调用

def build_max_heap(A):
    heap_size=len(A)
    P=A[:]
    for i in range(int(heap_size/2),0,-1):
        max_heapify(P,i,heap_size)
    return P

def heap_maximum(A):
    return A[0]

def heap_extract_max(A,heap_size):
    if heap_size<1:
        print("ERROR")
    max1=A[0]
    A[0]=A[heap_size-1]
    heap_size=heap_size-1
    max_heapify(A,1,heap_size)
    del(A[heap_size-1])
    return max1

def heap_increase_key(A,i,key):
    if key<A[i-1]:
        print("ERROR")
    A[i-1]=key
    parent=int(i/2)
    while(i>1 and A[parent-1]<A[i-1]):
        A[i-1],A[parent-1]=A[parent-1],A[i-1]
        i=parent
        parent=int(i/2)

def max_heap_insert(A,key):
    heap_size=len(A)+1
    A.append(-float("inf"))
    heap_increase_key(A,heap_size,key)

print("给定序列:                   "+str(v))
heap=build_max_heap(v)
print("当前最大堆:                 "+str(heap))
print("返回优先序列中的最大值:     "+str(heap_maximum(heap)))
print("当前最大堆:                 "+str(heap))
print("返回优先序列中的最大值并删除:"+str(heap_extract_max(heap,len(v))))
print("当前最大堆:                 "+str(heap))
heap_increase_key(heap,5,10000)
print("改写为10000的最大堆:        "+str(heap))
max_heap_insert(heap,10002)
print("插入10002的最大堆:          "+str(heap))

打印的结果为

给定序列:                   [33, 52, 91, 5, 85, 90, 51, 71, 57, 48]
当前最大堆:                 [91, 85, 90, 71, 52, 33, 51, 5, 57, 48]
返回优先序列中的最大值:     91
当前最大堆:                 [91, 85, 90, 71, 52, 33, 51, 5, 57, 48]
返回优先序列中的最大值并删除:91
当前最大堆:                 [90, 85, 51, 71, 52, 33, 48, 5, 48]
改写为10000的最大堆:        [10000, 90, 51, 71, 85, 33, 48, 5, 48]
插入10002的最大堆:          [10002, 10000, 51, 71, 90, 33, 48, 5, 48, 85]

以上就实现来最大优先序列,可以整合成类来使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wxyice

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值