Python数据结构与算法分析(第2版),数据结构python题库
首先简单解释一下小顶堆和大顶堆,它们的本质是一棵完整的二叉树。不同的是,除了叶子节点,小顶堆的每个父节点的键都小于左右子节点的键。大山的每个父节点的键大于其左右子节点的键。这里的键被理解为节点的值。Index是树中节点的索引或位置。小顶堆/大顶堆的特点是根节点必须是总数中最小或最大的元素,这也是区别于其他数据结构的最大特点。
以大堆为例,先说说它最重要的两个操作add和pop是如何实现的:
当您向现有的大型堆中添加元素时,add会将新元素作为树中的最后一个节点。
将新节点与父节点进行比较:如果新节点的值大于父节点的值,则将新节点的位置与父节点交换。实际上,两个元素的值是互换的。
通过重复上述过程,如果新节点小于父节点或者新节点的当前位置已经是根节点,则可以停止上述循环。至此,堆的更新完成,如果新节点的值大于父节点的值,则父节点和新节点的位置互换。此时,新节点11的值大于父节点10的值,交换继续。
流行音乐
从顶部堆中排出的元素是排出堆的根节点。也就是说,它是弹出窗口中值最大的元素。根节点被弹出后,堆的最后一个叶子节点必须移动到根节点的位置,这样堆还是一个大堆。
从根节点开始,比较根节点及其左右子节点的元素大小。如果根节点不比子节点大,根节点将与其更大的子节点交换。
只要有子节点,它就会继续比较父节点和左右子节点的大小,直到当前节点已经是叶节点或者其值大于左右子节点,然后停止循环,更新最大堆。
根节点5小于子节点12,因此根节点与较大的子节点交换。这意味着5和12交换5和8后,值为5的节点已经是叶节点,循环结束,最大堆更新完成。
直接点击下面的代码。
classmaxheap(对象) :
def __init__(self):
自我。_data=[]
自我。_count=0
defsize(自身) :
从.回来。_计数
efisempty(自我) :
回归自我。_count==0
efadd(self,x):
" "向最大堆添加元素:1。将新添加的元素作为最后一个叶节点添加到堆的末尾;2.判断当前节点及其父节点的大小:如果当前节点大于父节点,则交换两个节点的位置;然后,比较当前节点小于父节点的逻辑,即在_shiftUp函数中实现,直到:param x: return要添加到最大堆的元素:return:调整后的最大堆""
自我。_data.append(x))
自身传递的参数。_ shift _ up (self。_ count) # _ shift up是新添加节点的索引。
自我。_count=1
defpop(自身) :
" "从最大堆中弹出根节点,无疑是这个堆的最大元素;调整堆的结构,使新堆仍然是最大的堆。1.首先弹出根节点,也就是索引为0的元素,把最后一个叶子节点放在根节点的位置。2.从根节点开始,比较两个子节点的大小。如果当前节点小于子节点,则将当前节点与较大的子节点交换,继续下去,直到当前节点是叶节点或者当前节点大于子节点3360reeead。
如果自我。_计数:
ret=self。_data[0]
自我。_count -=1
自我。_data[0]=self。_data[-1]
自我。_shift_down(0)).
返回
def_shift_up(self,index):
Parent=(index -1) 1
wile索引0和自己。_ data [ index ] self。_ data [ parent ]:
自我。_data[index],self。_ data [ parent ]=self。_ data [父级],自身。_ data[索引]
索引=父级
Parent=(index -1) 1
def_shift_down(self,index):
Max _ child=(index 1) 1
而max_child自我。_计数:
#确定是否有正确的子节点。
ifmax _ child1self。_ countandself。_ data [ max _ child1] self。_ data [ max _ child ] 3360
max_child=max_child 1
如果自我。_data[index] self。_data[max_child]:
自我。_data[index],self。_data[max_child]=self。_data[index],self。_data[max_child]
index=max_child
max_child=(index 1) 1
否则:
破裂
小顶堆的实现思路和大顶堆基本类似。唯一不同的是,在更新堆时,停止条件由当前节点值大于左右子节点改为当前节点值小于左右子节点停止更新堆。理解大顶堆然后看小顶堆的实现代码就很简单了:
类MinHeap(对象):
def __init__(self):
自我。_data=[]
自我。_count=0
定义大小(自身):
回归自我。_计数
def isEmpty(self):
回归自我。_count==0
定义添加(自身,x):
自我。_data.append(x)
自我。_shift_up(self。_count)
自我。_count=1
定义弹出(自身):
如果自我。_计数:
ret=self。_data[0]
自我。_data[0]=self。_data[-1]
自我。_count -=1
自我。_shift_down(0)
返回ret
def _shift_up(self,index):
parent=(index-1) 1
而索引0和self。_data[index] self。_data[parent]:
#当前节点不是根节点,且当前节点的值小于其父节点,则将当前节点与其父节点交换。
自我。_data[index],self。_data[parent]=self。_ data[父级],自身。_ data[索引]
索引=父级
parent=(index-1) 1
def _shift_down(self,index):
# min_child第一个左侧子节点
min_child=(index 1) 1
而min_child self。_计数:
#如果右子节点存在且其值小于左节点的值,则min_child=右子节点。
if min_child 1 self。_计数和自我。_data[min_child 1] self。_data[min_child]:
min_child=min_child 1
如果自我。_data[index]=self。_data[min_child]:
破裂
自我。_data[index],self[min_child]=self。_data[min_child],self。_ data[索引]
index=min_child
min_child=(index 1) 1
另一种思路是,如果实现了大顶堆,那么push时元素反转,pop时元素反转,就可以得到小顶堆。理解其中一个,另一个就很简单了~ ~
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。