日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

dom4j实现为list添加父节点_Heap 堆的实现

發(fā)布時間:2025/3/12 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 dom4j实现为list添加父节点_Heap 堆的实现 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

堆(數(shù)據(jù)結(jié)構(gòu))

什么是堆

堆(Heap)是計(jì)算機(jī)科學(xué)中一類特殊的數(shù)據(jù)結(jié)構(gòu)的統(tǒng)稱。堆通常是一個可以被看做一棵完全二叉樹的數(shù)組對象

堆的性質(zhì)

這種用數(shù)組實(shí)現(xiàn)的二叉樹,假設(shè)節(jié)點(diǎn)的索引值為index,那么:

節(jié)點(diǎn)的左孩子節(jié)點(diǎn)是 2*index+1,

節(jié)點(diǎn)的右孩子節(jié)點(diǎn)是 2*index+2,

左孩子節(jié)點(diǎn)的父節(jié)點(diǎn)是 (index-1) / 2。

右孩子結(jié)點(diǎn)的父結(jié)點(diǎn)是 (index-2) / 2

最大堆中,父結(jié)點(diǎn)的值比每一個子節(jié)點(diǎn)的值都要大

最小堆中,父結(jié)點(diǎn)的值比每一個子節(jié)點(diǎn)的值都要小

堆的插入,取值

堆是一種數(shù)據(jù)結(jié)構(gòu),分為最小堆和最大堆,可以用二叉樹來表示。

在二叉樹的任意的一個三角結(jié)構(gòu)中(一個父節(jié)點(diǎn),兩個子節(jié)點(diǎn)),需要滿足以下兩個條件:

1、父節(jié)點(diǎn)要是最小的,就是最小堆(或最大的,就是最大堆),兩個子節(jié)點(diǎn)之間沒有要求

2、數(shù)據(jù)插入的順序是一層一層的,只有上一層存滿,才會有下一層

一、插入(insert)

假設(shè)我們有一個原始的最小堆如下:

插入操作:

當(dāng)插入一個新值時,首先將值放到樹的最后的位置,如下圖所示。

然后將這個值與父級元素比較,如果不滿足規(guī)則1,則與父元素替換(如下圖所示)。

第一步

第二步

第三步

二、取值操作

取最小值操作:

在最小堆中,拿出一個最小值,當(dāng)然就是拿出第一個數(shù)啦~不過拿完以后樹不就沒有“頭”了?

不用擔(dān)心,我們可以把最后一個數(shù)放到頭的位置,這樣樹的結(jié)構(gòu)就不會改變,而且操作簡單(因?yàn)槭亲詈笠粋€數(shù))并且不會改變完全二叉樹結(jié)構(gòu)。

當(dāng)然,因?yàn)槭亲詈笠粋€數(shù),必然會出現(xiàn)不滿足條件1的情況,所以我們需要把新的樹頭與子元素比較替換,下面是圖片演示:

假設(shè)我們有一個原始的最小堆如下所示,接下來我們要取最小值:

不過交換完很可能是不滿足條件1的,那么我們就需要比較替換,替換規(guī)則是和兩個子元素中最小的一個替換

由上面可以明白堆的插入與取值操作,那么我們接下來用代碼實(shí)現(xiàn)最大堆的操作

最大堆實(shí)現(xiàn)操作步驟

首先創(chuàng)建一個堆的類

1、初始化一個空堆,使用數(shù)組來存放堆元素,節(jié)省存儲

2、定義一個查找父結(jié)點(diǎn)的方法 get_parent_index 為插入,取值操作做準(zhǔn)備

首先判斷孩子結(jié)點(diǎn)下標(biāo):

當(dāng)孩子結(jié)點(diǎn)下標(biāo)為 0 時,證明此時孩子結(jié)點(diǎn)為根節(jié)點(diǎn),根節(jié)點(diǎn)沒有父結(jié)點(diǎn),返回None

當(dāng)孩子及誒點(diǎn)大于 當(dāng)前堆的元素值時,證明此時沒有該孩子結(jié)點(diǎn),孩子結(jié)點(diǎn)不遜在,那么 該孩子結(jié)點(diǎn)沒有父結(jié)點(diǎn)返回 None

當(dāng)孩子結(jié)點(diǎn)有父結(jié)點(diǎn)時,利用位運(yùn)算符 >> 求出當(dāng)前孩子結(jié)點(diǎn)的父結(jié)點(diǎn)下標(biāo)

3、定義交換兩個索引值的方法 swap 方法,利用列表的下標(biāo),交換兩個數(shù)值的位置

4、定義插入結(jié)點(diǎn)方法 insert 方法

先把元素放在最后面,然后往前依次堆化 (保證完全二叉樹結(jié)構(gòu))
這里以大頂堆為例,如果插入元素比父結(jié)點(diǎn)大,則交換,直到最后

(1) 把新添加的結(jié)點(diǎn)插入數(shù)組的最后面

(2) 找到新添加(最后一個) 元素的索引

(3) 找到該元素的父結(jié)點(diǎn)下標(biāo)

(4) 定義一個循環(huán),判斷當(dāng)前孩子結(jié)點(diǎn)與父結(jié)點(diǎn)大小

若當(dāng)孩子結(jié)點(diǎn)的值大于父結(jié)點(diǎn)時,不滿足最大堆的條件,將孩子結(jié)點(diǎn)與父結(jié)點(diǎn)交換位置

交換后,子節(jié)點(diǎn)上移后,再次判斷父結(jié)點(diǎn)下標(biāo),再次循環(huán)判斷直到該元素成為堆頂,或小于父結(jié)點(diǎn)(對于大頂堆)

5、定義取值 刪除堆頂元素 pop 方法

刪除堆頂元素,然后將最后一個元素放在堆頂,在從上往下依次堆化,保證完全二叉樹結(jié)構(gòu)

(1) 找到堆頂元素

(2) 把最后一個結(jié)點(diǎn)放到堆頂

(3) 刪除最后一個元素

(4) 從堆頂堆化,利用定義的 heapify 方法

(5) 返回刪除的結(jié)點(diǎn)元素值

6、定義堆化 heapify 方法

從上往下堆化,從 index 開始堆化操作 (大頂堆)

最大堆代碼實(shí)現(xiàn)

python

class Heap:def __init__(self):# 初始化一個空堆,使用數(shù)組來存放堆元素,節(jié)省存儲self.data_list = []def get_parent_index(self,child_index : int): # child_index : 孩子結(jié)點(diǎn)下標(biāo)"""返回父結(jié)點(diǎn)的下標(biāo)"""if child_index == 0 or child_index > len(self.data_list) - 1:return Noneelse:return (child_index - 1) >> 1# 如果某個結(jié)點(diǎn)的孩子結(jié)點(diǎn)空缺,數(shù)組對應(yīng)的位置也空缺# 假設(shè)一個父結(jié)點(diǎn)的下標(biāo)是 parent ,左孩子的下標(biāo)是 2*parent+1 ,右孩子下標(biāo)是 2*parent+2# 左孩子的下標(biāo)是 child,父結(jié)點(diǎn)的西下表是 (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é)點(diǎn)大,則交換,直到最后"""self.data_list.append(data) # 把新添加的結(jié)點(diǎn)插入數(shù)組的最后面curr_index = len(self.data_list) - 1 # 新添加(最后一個) 元素的索引curr_parent_index = self.get_parent_index(curr_index) # 找到該元素的父結(jié)點(diǎn)下標(biāo)# 循環(huán),直到該元素成為堆頂,或小于父結(jié)點(diǎn)(對于大頂堆)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é)點(diǎn)上移curr_parent_index = self.get_parent_index(curr_parent_index) # 再次判斷父結(jié)點(diǎn)def pop(self):"""刪除堆頂元素,然后將最后一個元素放在堆頂,在從上往下依次堆化"""del_data = self.data_list[0] # 找到堆頂元素self.data_list[0] = self.data_list[-1] # 把最后一個結(jié)點(diǎn)放到堆頂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é)點(diǎn)大于當(dāng)前最大結(jié)點(diǎn),最大值索引等于左孩子索引if 2 * index + 2 < size and self.data_list[2*index+2] > self.data_list[mv_idx]:mv_idx = 2 * index + 2 # 如果右孩子結(jié)點(diǎn)大于當(dāng)前最大結(jié)點(diǎn),最大值索引等于右孩子索引if mv_idx == index: # 如果當(dāng)孩子結(jié)點(diǎn)與最大值索引相等時,證明此時循環(huán)完成,退出循環(huán)breakself.swap(mv_idx,index) #交換最大值和當(dāng)前值index = mv_idx # 當(dāng)前值等于這一輪的最大值結(jié)點(diǎn)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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。