堆排序是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
堆排序的思路:
1、将原始数据按照完全二叉树的形式排列
2、按照堆积的性质,使子节点的键值总是小于它的父节点;即从下到上,从右到左,将所有非叶子节点的值与其叶子节点的值作比较,将较大值放在父节点
3、排列完成后,就是一个有序的堆,然后将堆顶元素R[0]与堆尾元素R[n-1]调换位置,之后将新的R[0]到R[n-2]的元素回到第二步,R[n-1]元素则是已经排列好的。
这里引用了百度百科中python的代码,之后补上自己的python版本和java版本
big_endian是将arr的前end+1个元素,从start开始进行排序。
在第一次初始化排序的时候,是big_endian(arr, 4, 9),big_endian(arr, 3, 9),big_endian(arr, 2, 9),big_endian(arr, 1, 9),big_endian(arr, 0, 9)。
为什么是倒序?如果从堆顶开始,那么某元素R[x],因为比其子节点小而与子节点交换值之后,就有可能比其父节点大了。
heap_sort中,first = len(arr)//2 - 1 直接确定了第一个非叶子节点的位置。第一个循环是将初始列表按照堆积的性质排列;第二个循环,是先将堆顶元素与堆尾元素交换位置,然后再将除堆尾元素之外的元素进行排序。
def big_endian(arr,start,end):
root=start
child=root*2+1 #左孩子
while child<=end:
#孩子比最后一个节点还大,也就意味着最后一个叶子节点了,就得跳出去一次循环,已经调整完毕
if child+1<=end and arr[child]<arr[child+1]:
#为了始终让其跟子元素的较大值比较,如果右边大就左换右,左边大的话就默认
child+=1
if arr[root]<arr[child]:
#父节点小于子节点直接交换位置,同时坐标也得换,这样下次循环可以准确判断:是否为最底层,
#是不是调整完毕
arr[root],arr[child]=arr[child],arr[root]
root=child
child=root*2+1
else:
break
def heap_sort(arr): #无序区大根堆排序
first=len(arr)//2 - 1
for start in range(first,-1,-1):
#从下到上,从左到右对每个节点进行调整,循环得到非叶子节点
big_endian(arr,start,len(arr)-1) #去调整所有的节点
for end in range(len(arr)-1,0,-1):
arr[0],arr[end]=arr[end],arr[0] #顶部尾部互换位置
big_endian(arr,0,end-1) #重新调整子节点的顺序,从顶开始调整
return arr
def main():
l=[3,1,4,9,6,7,5,8,2,10]
print(heap_sort(l))
if __name__=="__main__":
main()