堆排序之前一直感觉很难,因为在看堆排序的时候,都是讲的树结构,实际上在代码实现中,使用的是一维数组。仔细理解一下代码,发现其实没那么难。
从上图可以得到
- 父节点 i 的左孩子索引: 2*i+1
- 父节点 i 的右孩子索引: 2*i+2
- 叶子结点 j 的父节点索引 floor((j-1)/2)
堆排序代码实现
class Solution:
def heapsort(self,num):
le = len(num)
# 先建立大根堆,找到最大的元素置于堆顶,从下至上建堆
for i in range((le-1)//2,-1,-1):
self.fix(num,i,le-1)
# 将堆顶元素取出与未排序的最后一个元素交换,实现整个数组的排序
n = le-1
while n >= 0:
num[0],num[n] = num[n],num[0]
self.fix(num,0,n-1)
n -= 1
return num
#i 为需要调整元素的位置,e为结束位置
def fix(self,num,i,e):
while 2*i+1 <= e:
j = 2*i+1 # j为i的左孩子
# 如果右孩子存在且右孩子大于左孩子,则把值较大的索引赋给j
# j表示左右孩子中值较大的索引
if j < e and num[j]<num[j+1]:
j = j+1
# 如果父节点比较大的叶子结点值小,则交换叶子结点和父节点
# 此时目标元素i的位置变成了j,若i存在孩子,继续调整i和其叶子结点的位置
if num[i] < num[j]:
num[i],num[j] = num[j],num[i]
i = j
else:
break
if __name__== '__main__':
p = Solution()
num = [1,4,0,3,6,7,11,22,-1]
print(p.heapsort(num))
相关题目:
输入n个整数,找出其中最小的K个数(或最大的K个数)
思路:
取数组的前k个数,建立大小为k的大根堆,遍历剩余的n-k个元素,若小于堆顶元素,则替换掉堆顶值,并调整大根堆。遍历完后,再对堆进行排序输出即可。
代码如下:
# 最小的k个数方法
class MinK:
def GetLeastNumbers_Solution(self, tinput, k):
# write code here
le = len(tinput)
if k == 0:
return []
# 建立长度为k的大堆顶
if k <= le:
heap = tinput[:k]
else:
return []
hl = len(heap)
for i in range((hl-1)//2,-1,-1):
self.fix(heap,i,hl-1)
# 遍历剩余的元素
for i in tinput[hl:]:
if i < heap[0]:
heap[0] = i
self.fix(heap,0,hl-1)
# 整个排序
i = hl-1
while i > 0:
heap[0],heap[i] = heap[i],heap[0]
self.fix(heap,0,i-1)
i -= 1
return heap
def fix(self,num,i,e):
while 2*i+1 <= e:
j = 2*i+1 # j为i的左孩子
# 如果右孩子存在且右孩子大于左孩子,则把值较大的索引赋给j
# j表示左右孩子中值较大的索引
if j < e and num[j]<num[j+1]:
j = j+1
# 如果父节点比较大的叶子结点值小,则交换叶子结点和父节点
# 此时目标元素i的位置变成了j,若i存在孩子,继续调整i和其叶子结点的位置
if num[i] < num[j]:
num[i],num[j] = num[j],num[i]
i = j
else:
break
# Top K 方法
class TopK:
def GetTopNumbers_Solution(self, tinput, k):
# write code here
le = len(tinput)
if k == 0:
return []
# 建立长度为k的小堆顶
if k <= le:
heap = tinput[:k]
else:
k = le
heap = tinput
hl = len(heap)
for i in range((hl-1)//2,-1,-1):
self.fix(heap,i,hl-1)
# 遍历剩余的元素
for i in tinput[hl:]:
if i > heap[0]:
heap[0] = i
self.fix(heap,0,hl-1)
# 整个排序
i = hl-1
while i > 0:
heap[0],heap[i] = heap[i],heap[0]
self.fix(heap,0,i-1)
i -= 1
return heap
#i 为需要调整元素的位置,e为结束位置
def fix(self,num,i,e):
while 2*i+1 <= e:
j = 2*i+1 # j为i的左孩子
if j < e and num[j]>num[j+1]:
j = j+1
# 如果父节点比较大的叶子结点值大,则交换叶子结点和父节点
# 此时目标元素i的位置变成了j,若i存在孩子,继续调整i和其叶子结点的位置
if num[i] > num[j]:
num[i],num[j] = num[j],num[i]
i = j
else:
break