堆排序
算法描述
堆排序算法具有空间原址性,(二叉)堆是一个数组,它近似完全二叉树,树上的每一个节点对应数组中的一个元素,除了最底层外,该树是>完满的,而且从左向右填充。
最大堆性质
最大堆指的是对于某个节点,其值一定不小于其左右子节点的值,不大于其父节点的值: Arr[PARENT(i)]>=ARR[i]。
算法思想
首先,利用最大堆性质,将序列建成最大堆,因为数组中最大元素总在根节点Arr[1]中,通过把它与Arr[n]进行交换,然后将最后的节点从堆中去掉,新根节点可能会违背最大堆性质,因此对剩余节点进行调整以维护最大堆性质。因此算法步骤为:
- 建立最大堆
- 循环:
- 交换堆中第一个元素与最后一个元素
- 去除堆中最后一个节点
- 维护最大堆性质
伪代码为:
- HEAPOSORT(A)
- BUILD-MAX-HEAP(A)
- for i =A.length downto 2
- exchange A[1] with A[i]
- A.heap-size=A.heap-size-1
- 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)
参考
《算法导论》第三版