使用python實現一個大頂堆

堆定義

  • 堆是一個樹形結構,其底層實現是一棵完全二叉樹。而完全二叉樹是一層一層按照進入的順序排成的。按照這個特性,我們可以用數組來按照完全二叉樹實現堆;

堆的一些性質

一個大頂堆示例

上面的示例就是一個完全二叉樹,也是一個大頂堆。而大頂堆有一個性質:每一個節點的值都小于它父節點的值。(特別注意,每一個節點的值的大小與它所處的深度沒有必然的聯系。)

我們可以很容易的根據任意一個節點的索引(除去根節點)找到它的父節點的索引以及其左右子節點的索引,如果當前節點的索引為index,那么:

  • 當前節點的父節點 = (index-1) / 2 (這里我們將結果取整);
  • 當前節點的左子節點 = index * 2 + 1;
  • 當前節點的右子節點 = index * 2 + 2。

代碼實現一個堆

根據上述的堆的一些性質,我們可以自己實現一個堆。

# 實現一個最大堆
class MaxHeap(object):
    """
    實現一個大頂堆
    """

    def __init__(self):
        self.array = [] # 用一個數組存放堆中元素

    def heapify(self, array):
        """
        對傳入的數組進行堆化
        """
        for a in array:
            self.push(a)
        return self.array

    def get_size(self):
        """
        返回堆的大小
        """
        return len(self.array)

    def _parent(self, index):
        """
        返回某個節點的父節點
        """
        if index == 0:
            raise Exception('Index 0 has no parent')
        return int((index - 1) / 2)

    def _left_child(self, index):
        """
        返回左孩子節點的索引
        """
        return index * 2 + 1

    def _right_child(self, index):
        """
        返回右邊孩子節點的索引
        """
        return index * 2 + 2

    def _shift_up(self, k):
        """
        節點上移動,將當前節點與其父親節點比較大小,如果比父親節點大,
        則交換其位置,重復只執行上述過程,直到當前節點比父親節點小。
        """
        while k > 0 and self.array[self._parent(k)] < self.array[k]:
            # 交換節點與父節點的值
            self.array[self._parent(k)], self.array[k] = self.array[k], self.array[self._parent(k)]
            k = self._parent(k)

    def _shift_down(self, k):
        """
        節點下移動, 當前節點與它左右孩子中最大的節點交換位置
        """
        while self._left_child(k) < self.get_size():
            choose_index = self._left_child(k)  # 左孩子的索引
            # 先比較左右孩子的大小,選擇較大的那個孩子再與父親節點進行比較
            if choose_index + 1 < self.get_size() and self.array[choose_index + 1] > self.array[choose_index]:
                choose_index = self._right_child(k)
            if self.array[choose_index] <= self.array[k]:  # 如果最大的孩子比父親節點小,退出循環
                break
            # 否則父親節點和最大的子節點交換位置
            self.array[choose_index], self.array[k] = self.array[k], self.array[choose_index]
            k = choose_index  # 進行下次循環

    def push(self, value):
        """
        添加一個元素后,需要對堆重新進行堆化,具體過程就是對堆尾元素執行上移操作;
        """
        self.array.append(value)
        self._shift_up(self.get_size() - 1)  # 相當于對堆進行重新堆化

    def pop(self):
        """
        返回堆頂元素,將堆頂元素和堆最后一個元素交換,
        然后返回最后一個元素,最后對堆頂元素進行下沉操作(重新堆化)
        """
        ret = self.find_max()
        self.array[0], self.array[self.get_size() - 1] = self.array[self.get_size() - 1], self.array[0]
        self.array.pop(-1)  # 刪除最后一個元素
        self._shift_down(0)
        return ret

    def find_max(self):
        """
        查看堆中的最大值
        """
        if self.array:
            return self.array[0]
        else:
            raise Exception('Empty heap has no value')

# 測試我們實現的大頂堆
test = [12, 11, 10, 9, 6, 7, 8, 13]
max_heap = MaxHeap()
print(max_heap.heapify(test)) # 對一個數組執行堆化
print(max_heap.pop()) # 彈出堆頂元素
print(max_heap.array) 
max_heap.push(14) # 推入一個元素
print(max_heap.array)
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 二叉堆 說明 在閱讀該文章的時候,最好手中有一只紙和筆能夠畫出二叉堆的結構,會更加容易理解。 二叉樹的定義 二叉樹...
    CoderCat閱讀 387評論 0 1
  • 上一篇:Java集合-ConcurrentHashMap工作原理和實現JDK8 本文學習知識點 1、二叉查找樹,以...
    Misout閱讀 13,913評論 9 67
  • 思考 現在有如下需求,設計一種數據結構,用來存放整數,要求提供3個接口 添加元素 獲取最大值 刪除最大值 通過我們...
    ducktobey閱讀 870評論 0 1
  • 1)這本書為什么值得看: Python語言描述,如果學的Python用這本書學數據結構更合適 2016年出版,內容...
    孫懷闊閱讀 12,566評論 0 15
  • 每一位來到世界的生命,都有著他注定的責任和義務,是渾渾噩噩呢!還是豐富多彩呢!就好比雪糕一樣,精心的制作只為取悅他...
    夢彡先生閱讀 138評論 0 1