python 實現堆排序

一、概念

  • 堆排序是利用 堆進行排序的python

  • 堆是一種徹底二叉樹web

  • 堆有兩種類型: 大根堆 小根堆數組

  • 兩種類型的概念以下:app

    大根堆:每一個結點的值都大於或等於左右孩子結點
    小根堆:每一個結點的值都小於或等於左右孩子結點
    在這裏插入圖片描述
    在這裏插入圖片描述svg

徹底二叉樹

徹底二叉樹 是 一種除了最後一層以外的其餘每一層都被徹底填充,而且全部結點都保持向左對齊的樹,向左對齊指的是:
在這裏插入圖片描述函數

下面這樣的樹不是徹底二叉樹:
在這裏插入圖片描述ui

若是給上面的大小根堆的根節點從1開始編號,則知足下面關係(下圖就知足這個關係):

在這裏插入圖片描述

若是把這些數字放入數組中,則以下圖所示:其中,上面的數字是數組下標值,第一個元素佔位用。
在這裏插入圖片描述編碼

堆排序的思想(以大根堆爲例)

  • 首先將待排序的數組構造出一個大根堆
  • 取出這個大根堆的堆頂節點(最大值),與堆的最下最右的元素進行交換,而後把剩下的元素再構造出一個大根堆
  • 重複第二步,直到這個大根堆的長度爲1,此時完成排序。

下面經過圖片看第二步是如何進行的
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述spa

這就是構建大根堆的思想,瞭解了以後就能夠進行編碼,編碼主要解決兩個問題:

  • 如何把一個序列構造出一個大根堆3d

  • 輸出堆頂元素後,如何使剩下的元素構造出一個大根堆

    根據問題進行編碼,因爲數組下標是從0開始的,而樹的節點從1開始,咱們還須要引入一個輔助位置,Python提供的原始數據類型list其實是一個線性表(Array),因爲咱們須要在序列最左邊追加一個輔助位,線性表這樣作的話開銷很大,須要把數組總體向右移動,因此list類型沒有提供形如appendleft的函數,可是在一個鏈表裏作這種操做就很簡單了,Python的collections庫裏提供了鏈表結構deque,咱們先使用它初始化一個無序序列:

from collections import deque
L = deque([50, 16, 30, 10, 60, 90, 2, 80, 70])
   
L.appendleft(0)

總代碼:

from collections import deque

def swap_param(L, i, j):
    L[i], L[j] = L[j], L[i]
    return L

def heap_adjust(L, start, end):
    temp = L[start]

    i = start
    j = 2 * i

    while j <= end:
        # L[j] 爲左右葉子節點中相對大的數字
        if (j < end) and (L[j] < L[j + 1]):
            j += 1
        # 將根結點與葉子節點中較大的數交換
        if temp < L[j]:
            L[i], L[j] = L[j],L[i]
            i = j
            j = 2 * i
        else:
            break
    # L[i] = temp

def heap_sort(L):
    L_length = len(L) - 1

    first_sort_count = L_length // 2
    for i in range(first_sort_count):
        heap_adjust(L, first_sort_count - i, L_length)

    for i in range(L_length - 1):
        L = swap_param(L, 1, L_length - i)
        heap_adjust(L, 1, L_length - i - 1)

    return [L[i] for i in range(1, len(L))]

def main():
    L = deque([50, 16, 30, 10, 60, 90, 2, 80, 70])
    # L = deque([56,30,71,18,29,93,44,75,20,65,68,34])
    L.appendleft(0)
    print(heap_sort(L))

if __name__ == '__main__':
    main()