常用排序算法:堆排序

算法思路:

堆:分为大根堆和小根堆
       大根堆:一棵完全二叉树,满足任意一节点都比其孩子节点大。
       小根堆:一棵完全二叉树,满足任意一节点都比其孩子节点小。

堆排序流程: 

  1. 构造堆
  2. 得到堆顶元素,为最大元素
  3. 去掉堆顶,将堆的最后一个元素放到堆顶,然后调整重新使堆有序
  4. 堆顶元素为第二大的元素
  5. 重复第三步直到堆变空

例如以[4, 5, 3, 6, 1, 2 ]为例:

准备知识:

     在以顺序储存的完全二叉树中,父子节点的关系(下标):

  1. 父节点和左孩子:左孩子下标 = 父节点下标 * 2 + 1
  2. 父节点和右孩子:右孩子下标 = 父节点下标 * 2 + 2
  3. 子节点和父节点: 父节点下标 = (子节点下标 - 1)  // 2
  4. 最后一个非叶子节点:n // 2 -1

代码实现:  

def sift(nums, low, high):
    """
    调整堆,使堆有序
    :param nums: list
    :param low: 根节点
    :param high: 尾节点(树的最后一个)
    :return:
    """
    temp = nums[low]
    i = low
    j = 2 * i + 1
    while j <= high:  # 当前i位置为叶子节点, j超过high了
        # 找更大的子节点
        if j + 1 <= high and nums[j+1] > nums[j]:  #
            j = j + 1
        if temp < nums[j]:
            nums[i] = nums[j]
            i = j
            j = 2 * i + 1
        else:   # temp 大于两个子节点
            break
    nums[i] = temp


def heap_sort(nums):
    # 建堆
    l = len(nums)
    for i in range(l//2-1, -1, -1):
        # i是建堆时要调整的子树的根节点下标
        sift(nums, i, l-1)
    for i in range(l - 1, -1, -1):
        # 当前的high值
        nums[i], nums[0] = nums[0], nums[i]
        sift(nums, 0, i-1)

内置函数:

Python内置模块heapq帮我们实现了堆排序,内置函数用的是小根堆,上面的代码是大根堆,差别不大,heapq模块主要包括三个函数:

  1. heapify(list) 建小根堆   把传入的list变成小根堆

  2. heappush(heap_list, item)向已经建好的堆中增加数据

  3. heappop(heap_list) 输出小根堆中最小值

import heapq

nums = [3, 2, 1, 0, 6]

heapq.heapify(nums)
print(nums)
# [0, 2, 1, 3, 6]
heapq.heappush(nums, 4)
print(nums)
# [0, 2, 1, 3, 6, 4]
print(heapq.heappop(nums))
# 0
print(heapq.heappop(nums))
# 1
print(heapq.heappop(nums))
# 2

猜你喜欢

转载自blog.csdn.net/FanMLei/article/details/83307316