python實現各種常用算法之數據結構(5)

python實現堆的操作


堆的介紹

堆 (heap) 是一種經過排序的完全二叉樹,其中任一非葉子節點的值均不大於(或不小於)其左孩子和右孩子節點的值。
堆,又被爲優先隊列(priority queue)。儘管名爲優先隊列,但堆並不是隊列。

  1. 最大堆 根結點的鍵值是所有堆結點鍵值中最大者
  2. 最小堆 根結點的鍵值是所有堆結點鍵值中最小者。

最大堆

在這裏插入圖片描述

最小堆

在這裏插入圖片描述


基本功能實現

堆有兩點需要了解,

  1. 一是堆一般採用完全二叉樹;
  2. 二是堆中的每一個節點都大於其左右子節點(大頂堆), 或者堆中每一個節點都小於其左右子節點(小頂堆)。
  • 創建 heap 類
class heap(object):
    def __init__(self):
        # 初始化一個空堆,使用數組來在存放堆元素,節省存儲
        self.data_list = []
  • 添加 get_parent_index 函數
   def get_parent_index(self,index):
        if index == 0 or index > len(self.data_list) -1:
            return None
        # 返回父節點的下標
        else:
            # >> 是右移動運算符
            # 將 >> 左邊的運算數二進位全部移動
            # 例:2 >> 1 的結果爲 1
            # 該操作本質爲 0000 0010 運算後爲 0000 0001
            return (index -1) >> 1
    def swap(self,index_a,index_b):
        # 交換數組中的兩個元素
        self.data_list[index_a], self.data_list[index_b] = self.data_list[index_b], self.data_list[index_a]
  • 添加 insert 函數
def insert(self, data):
    # 先把元素放在最後,然後從後往前依次堆化
    # 這裏以大頂堆爲例,如果插入元素比父節點大,則交換,直到最後
    self.data_list.append(data)
    index = len(self.data_list) - 1
    parent = self.get_parent_index(index)
    # 循環,直到該元素成爲堆頂,或小於父節點(對於大頂堆)
    while parent is not None and self.data_list[parent] < self.data_list[index]:
        # 交換操作
        self.swap(parent, index)
        index = parent
        parent = self.get_parent_index(parent)
  • 添加 removeMax 函數
def removeMax(self):
    # 刪除堆頂元素,然後將最後一個元素放在堆頂,再從上往下依次堆化
    remove_data = self.data_list[0]
    self.data_list[0] = self.data_list[-1]
    del self.data_list[-1]

    # 堆化
    self.heapify(0)
    return remove_data
  • 添加 heapify 函數
def heapify(self,index):
    # 從上往下堆化,從 index 開始堆化操作 (大頂堆)
    total_index = len(self.data_list) -1
    while True:
        maxvalue_index = index
        if 2*index +1 <=  total_index and self.data_list[2*index +1] > self.data_list[maxvalue_index]:
            maxvalue_index = 2*index +1
        if 2*index +2 <=  total_index and self.data_list[2*index +2] > self.data_list[maxvalue_index]:
            maxvalue_index = 2*index +2
        if maxvalue_index == index:
            break
        self.swap(index,maxvalue_index)
        index = maxvalue_index

實例應用

請將 元素 1-10 放進堆,並展示建堆情況,及刪除堆頂元素情況

實例如下:

建堆: [10, 9, 6, 7, 8, 2, 5, 1, 4, 3]

刪除堆頂元素: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

實現代碼

class heap(object):
    def __init__(self):
        # 初始化一個空堆,使用數組來存放堆元素,節省存儲
        self.data_list = []

    def get_parent_index(self, index):
        #索引爲0,或者大於最大長度無父節點下標
        if index == 0 or index > len(self.data_list) - 1:
            return None
        # 返回父節點的下標
        else:
            # >> 是右移動運算符
            # 將 >> 左邊的運算數二進位全部移動
            # 例:2 >> 1 的結果爲 1
            # 該操作本質爲 0000 0010 運算後爲 0000 0001
            # 二進制中右移一位,相當於除二
            return (index - 1) >> 1

    def swap(self, index_a, index_b):
        # 交換數組中的兩個元素
        self.data_list[index_a], self.data_list[index_b] = self.data_list[index_b], self.data_list[index_a]

    def insert(self, data):
        # 先把元素放在最後,然後從後向前依次堆化
        # 這裏以大頂堆爲例,如果插入的元素比父節點大,則交換,直到最後

        #新元素添加到列表
        self.data_list.append(data)
        #最大長度
        index = len(self.data_list) - 1
        #獲取當前下標的父節點
        parent = self.get_parent_index(index)
        """
        插入新元素後進行堆化,從下往上
        1 獲取新元素的父節點,與父節點進行比較,若大於則交換
        2 循環,直到該元素成爲堆頂,或小於父節點(對於大頂堆)
        """
        while parent is not None and self.data_list[parent] < self.data_list[index]:
            # 交換操作
            self.swap(parent, index)
            #當前指針指向父節點
            index = parent
            #求當前指針的父節點
            parent = self.get_parent_index(parent)

    def removeMax(self):
        # 刪除堆頂元素,然後將最後一個元素放在堆頂,再從上往下依次堆化

        #暫存堆頂元素
        remove_data = self.data_list[0]
        #最後一個元素覆蓋到堆頂元素
        self.data_list[0] = self.data_list[-1]
        #刪除最後一個元素
        del self.data_list[-1]

        # 堆化
        self.heapify(0)
        #返回刪除的堆頂元素
        return remove_data

    def heapify(self, index):
        # 從上往下堆化,從index開始堆化操作(大頂堆)

        #索引的可取最大值即數組最大長度
        total_index = len(self.data_list) - 1
        while True:
            #初始化最大值元素的下標
            maxvalue_index = index
            #若當前下標的左右子樹結點的值大於最大值下標的值,則交換
            if 2 * index + 1 <= total_index and self.data_list[2 * index + 1] > self.data_list[maxvalue_index]:
                maxvalue_index = 2 * index + 1
            if 2 * index + 2 <= total_index and self.data_list[2 * index + 2] > self.data_list[maxvalue_index]:
                maxvalue_index = 2 * index + 2
            if maxvalue_index == index:
                break
            self.swap(index, maxvalue_index)
            #當前下標指向最大值下標,繼續循環進行同樣比較
            index = maxvalue_index

if __name__ == '__main__':
    myheap = heap()
    for i in range(10):
        myheap.insert(i + 1)
    print('建堆:', myheap.data_list)
    print("刪除堆頂元素:", [myheap.removeMax() for _ in range(10)])

運行結果

在這裏插入圖片描述

發佈了129 篇原創文章 · 獲贊 347 · 訪問量 60萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章