1. 程式人生 > 其它 >手寫堆排序

手寫堆排序

參考:https://zhongqiang.blog.csdn.net/article/details/115319669


class S():
    def __init__(self) -> None:
        pass

    # 堆排序
    def heapify(self, tree, n, i):
        """把父節點和最大子節點交換
        :param n: 總共的節點個數
        :param i: 元素的索引, 對第i個元素做heapify
        """
        # if i >= n:      # 遞迴出口 0 <= i <= (n-1),但是由於並不會越界,此處不需要遞迴出口
        #     return
        c1 = 2 * i + 1   # 左邊子節點
        c2 = 2 * i + 2   # 右邊子節點

        # 找出父節點&兩個子節點中最大的節點
        max_ele = i         # 假設父節點為最大值
        if c1 < n and tree[c1] > tree[max_ele]: max_ele = c1
        if c2 < n and tree[c2] > tree[max_ele]: max_ele = c2
        if max_ele != i:
            tree[max_ele], tree[i] = tree[i], tree[max_ele]
            # 遞迴 如果原先是max_ele節點,這裡會被調換過,就是比較大的值被拿到父節點,換來了一個比較小的數,需要往下遞迴下去
            self.heapify(tree, n, max_ele)    
        
    def build_heap(self, tree, n):
        """建堆;
        :param n: 陣列的長度或者節點的個數
        """
        last_node = n - 1         # 最後一個節點
        parent = (last_node - 1) // 2      # 最後一個節點對應的父節點

        # 從最後一個非葉子節點逆序遍歷, 調整建堆
        for i in range(parent, -1, -1):
            self.heapify(tree, n, i)
        
    def HeapSort(self, tree, n):
        # tree 陣列,n 長度
        """堆排序"""
        
        self.build_heap(tree, n)

        for i in range(n - 1, -1, -1):
            # 最後一個節點和最頂上的節點交換
            tree[0], tree[i] = tree[i], tree[0]
            # 拿出(砍斷)最後一個節點(上一步交換完後最大的數已經在最後了),
            # 而後從最頂上節點開始 heapify,又往下遞迴,直到形成穩定堆
            # 此處 heapify的引數是 i 而不是 n,因為不斷砍斷以後,整個陣列長度從 n 變成了 i
            self.heapify(tree, i, 0)
            
        return tree


s = S()
nums = [1, 3, 2, 6, 2, 0, 4, 8, 1]
print(s.HeapSort(nums, len(nums)))
# [0, 1, 1, 2, 2, 3, 4, 6, 8]