与堆相关的数据结构
最大堆的特点
堆排序使用的是二叉堆中的最大堆,即:根节点大于所有的子节点,而左右子节点之间没有大小关系。
二叉堆的构造:用一个一维数组存放即可,第i个节点的左右两个子节点分别在2*i, 2*i+1的位置。
堆排序的思路
二叉堆排序的思路:自底向上调整堆,使其满足最大堆的性质,此时根节点就是最大的元素。将根节点与最有一个节点交换之后,将1——n-1个元素看做一个新的堆,再重新调整堆,找到第二大的元素,与新堆最后元素交换,重复上述过程。
python实现:
import random
def adjust_heap(lst, n):
'''
调整堆为最大堆
:param lst: 存放堆的列表
:param n: 堆的长度
:return:
'''
node_position = int(n/2) #根据堆的性质,算出最后一个非叶子节点的位置
while node_position >= 1:
node = node_position -1
left_node = node_position*2 -1
right_node = node_position*2 + 1 -1
#分别判断左右节点是否存在,存在则判断是否需要调整
if left_node < n:
if lst[left_node] > lst[node]:
lst[left_node], lst[node] = lst[node], lst[left_node]
if right_node < n:
if lst[right_node] > lst[node]:
lst[right_node], lst[node] = lst[node], lst[right_node]
node_position -= 1
def heap_sort(lst):
for i in range(len(lst))[-1::-1]:
if i == 0:
return lst
else:
adjust_heap(lst, i+1) #调整为最大堆
lst[0], lst[i] = lst[i], lst[0] #将最大元素放置末尾
def main():
unsorted = [random.randint(0, 99) for _ in range(20)]
print(unsorted)
print(heap_sort(unsorted))
if __name__ == '__main__':
main()
输出:
[94, 2, 5, 57, 76, 61, 16, 45, 84, 67, 28, 56, 2, 3, 96, 58, 17, 28, 13, 26]
[2, 2, 3, 5, 13, 16, 17, 26, 28, 28, 45, 56, 57, 58, 61, 67, 76, 84, 94, 96]
堆排序是稳定的,即不会交换相等元素的位置
堆排序的空间复杂度是O(1),即没有使用额外的空间
堆排序的时间复杂度是O(n*log(n))