dom4j实现为list添加父节点_Heap 堆的实现
堆(數(shù)據(jù)結(jié)構(gòu))
什么是堆
堆(Heap)是計算機科學(xué)中一類特殊的數(shù)據(jù)結(jié)構(gòu)的統(tǒng)稱。堆通常是一個可以被看做一棵完全二叉樹的數(shù)組對象
堆的性質(zhì)
這種用數(shù)組實現(xiàn)的二叉樹,假設(shè)節(jié)點的索引值為index,那么:
節(jié)點的左孩子節(jié)點是 2*index+1,
節(jié)點的右孩子節(jié)點是 2*index+2,
左孩子節(jié)點的父節(jié)點是 (index-1) / 2。
右孩子結(jié)點的父結(jié)點是 (index-2) / 2
最大堆中,父結(jié)點的值比每一個子節(jié)點的值都要大
最小堆中,父結(jié)點的值比每一個子節(jié)點的值都要小
堆的插入,取值
堆是一種數(shù)據(jù)結(jié)構(gòu),分為最小堆和最大堆,可以用二叉樹來表示。
在二叉樹的任意的一個三角結(jié)構(gòu)中(一個父節(jié)點,兩個子節(jié)點),需要滿足以下兩個條件:
1、父節(jié)點要是最小的,就是最小堆(或最大的,就是最大堆),兩個子節(jié)點之間沒有要求
2、數(shù)據(jù)插入的順序是一層一層的,只有上一層存滿,才會有下一層
一、插入(insert)
假設(shè)我們有一個原始的最小堆如下:
插入操作:
當(dāng)插入一個新值時,首先將值放到樹的最后的位置,如下圖所示。
然后將這個值與父級元素比較,如果不滿足規(guī)則1,則與父元素替換(如下圖所示)。
第一步
第二步
第三步
二、取值操作
取最小值操作:
在最小堆中,拿出一個最小值,當(dāng)然就是拿出第一個數(shù)啦~不過拿完以后樹不就沒有“頭”了?
不用擔(dān)心,我們可以把最后一個數(shù)放到頭的位置,這樣樹的結(jié)構(gòu)就不會改變,而且操作簡單(因為是最后一個數(shù))并且不會改變完全二叉樹結(jié)構(gòu)。
當(dāng)然,因為是最后一個數(shù),必然會出現(xiàn)不滿足條件1的情況,所以我們需要把新的樹頭與子元素比較替換,下面是圖片演示:
假設(shè)我們有一個原始的最小堆如下所示,接下來我們要取最小值:
不過交換完很可能是不滿足條件1的,那么我們就需要比較替換,替換規(guī)則是和兩個子元素中最小的一個替換
由上面可以明白堆的插入與取值操作,那么我們接下來用代碼實現(xiàn)最大堆的操作
最大堆實現(xiàn)操作步驟
首先創(chuàng)建一個堆的類
1、初始化一個空堆,使用數(shù)組來存放堆元素,節(jié)省存儲
2、定義一個查找父結(jié)點的方法 get_parent_index 為插入,取值操作做準(zhǔn)備
首先判斷孩子結(jié)點下標(biāo):
當(dāng)孩子結(jié)點下標(biāo)為 0 時,證明此時孩子結(jié)點為根節(jié)點,根節(jié)點沒有父結(jié)點,返回None
當(dāng)孩子及誒點大于 當(dāng)前堆的元素值時,證明此時沒有該孩子結(jié)點,孩子結(jié)點不遜在,那么 該孩子結(jié)點沒有父結(jié)點返回 None
當(dāng)孩子結(jié)點有父結(jié)點時,利用位運算符 >> 求出當(dāng)前孩子結(jié)點的父結(jié)點下標(biāo)
3、定義交換兩個索引值的方法 swap 方法,利用列表的下標(biāo),交換兩個數(shù)值的位置
4、定義插入結(jié)點方法 insert 方法
先把元素放在最后面,然后往前依次堆化 (保證完全二叉樹結(jié)構(gòu))
這里以大頂堆為例,如果插入元素比父結(jié)點大,則交換,直到最后
(1) 把新添加的結(jié)點插入數(shù)組的最后面
(2) 找到新添加(最后一個) 元素的索引
(3) 找到該元素的父結(jié)點下標(biāo)
(4) 定義一個循環(huán),判斷當(dāng)前孩子結(jié)點與父結(jié)點大小
若當(dāng)孩子結(jié)點的值大于父結(jié)點時,不滿足最大堆的條件,將孩子結(jié)點與父結(jié)點交換位置
交換后,子節(jié)點上移后,再次判斷父結(jié)點下標(biāo),再次循環(huán)判斷直到該元素成為堆頂,或小于父結(jié)點(對于大頂堆)
5、定義取值 刪除堆頂元素 pop 方法
刪除堆頂元素,然后將最后一個元素放在堆頂,在從上往下依次堆化,保證完全二叉樹結(jié)構(gòu)
(1) 找到堆頂元素
(2) 把最后一個結(jié)點放到堆頂
(3) 刪除最后一個元素
(4) 從堆頂堆化,利用定義的 heapify 方法
(5) 返回刪除的結(jié)點元素值
6、定義堆化 heapify 方法
從上往下堆化,從 index 開始堆化操作 (大頂堆)
最大堆代碼實現(xiàn)
python
class Heap:def __init__(self):# 初始化一個空堆,使用數(shù)組來存放堆元素,節(jié)省存儲self.data_list = []def get_parent_index(self,child_index : int): # child_index : 孩子結(jié)點下標(biāo)"""返回父結(jié)點的下標(biāo)"""if child_index == 0 or child_index > len(self.data_list) - 1:return Noneelse:return (child_index - 1) >> 1# 如果某個結(jié)點的孩子結(jié)點空缺,數(shù)組對應(yīng)的位置也空缺# 假設(shè)一個父結(jié)點的下標(biāo)是 parent ,左孩子的下標(biāo)是 2*parent+1 ,右孩子下標(biāo)是 2*parent+2# 左孩子的下標(biāo)是 child,父結(jié)點的西下表是 (child - 1)/2def swap(self,index_a,index_b):'''交換兩個索引對應(yīng)的值:param index_a: a索引:type index_a: int:param index_b: b索引:type index_b: int:return::rtype:'''self.data_list[index_a],self.data_list[index_b] = self.data_list[index_b],self.data_list[index_a]def insert(self,data : int):"""先把元素放在最后面,然后往前依次堆化 (保證完全二叉樹結(jié)構(gòu))這里以大頂堆為例,如果插入元素比父結(jié)點大,則交換,直到最后"""self.data_list.append(data) # 把新添加的結(jié)點插入數(shù)組的最后面curr_index = len(self.data_list) - 1 # 新添加(最后一個) 元素的索引curr_parent_index = self.get_parent_index(curr_index) # 找到該元素的父結(jié)點下標(biāo)# 循環(huán),直到該元素成為堆頂,或小于父結(jié)點(對于大頂堆)while curr_parent_index is not None and self.data_list[curr_parent_index] < self.data_list[curr_index]:self.swap(curr_parent_index,curr_index) # 利用 swap 交換操作curr_index = curr_parent_index # 結(jié)點上移curr_parent_index = self.get_parent_index(curr_parent_index) # 再次判斷父結(jié)點def pop(self):"""刪除堆頂元素,然后將最后一個元素放在堆頂,在從上往下依次堆化"""del_data = self.data_list[0] # 找到堆頂元素self.data_list[0] = self.data_list[-1] # 把最后一個結(jié)點放到堆頂del self.data_list[-1] # 刪除最后一個元素self.heapify(0) # 從堆頂堆化,利用定義的 heapify 方法return del_data # 返回刪除的元素def heapify(self,index):"""從上往下堆化,從 index 開始堆化操作 (大頂堆)"""size = len(self.data_list) - 1 # 數(shù)組的長度while True:mv_idx = index # mx_idx 代表最大值索引if 2 * index + 1 < size and self.data_list[2*index+1] > self.data_list[mv_idx]:mv_idx = 2 * index + 1 # 如果左孩子結(jié)點大于當(dāng)前最大結(jié)點,最大值索引等于左孩子索引if 2 * index + 2 < size and self.data_list[2*index+2] > self.data_list[mv_idx]:mv_idx = 2 * index + 2 # 如果右孩子結(jié)點大于當(dāng)前最大結(jié)點,最大值索引等于右孩子索引if mv_idx == index: # 如果當(dāng)孩子結(jié)點與最大值索引相等時,證明此時循環(huán)完成,退出循環(huán)breakself.swap(mv_idx,index) #交換最大值和當(dāng)前值index = mv_idx # 當(dāng)前值等于這一輪的最大值結(jié)點if __name__ == '__main__':myheap = Heap()for i in range(10):myheap.insert(i + 1)print("建堆:",myheap.data_list)print("刪除堆頂元素:",[myheap.pop() for i in range(10)])總結(jié)
以上是生活随笔為你收集整理的dom4j实现为list添加父节点_Heap 堆的实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: keyshot怎么让物体发光_户外发光字
- 下一篇: ccf魔数c语言,ccf 201609-