【数据结构】大根堆和左高树

【数据结构】5.大根堆和左高树 - 代码实现icon-default.png?t=N7T8https://www.cnblogs.com/stux/p/17755003.html1.大根堆

1.1 定义

  大根树:树中的每一个节点的值都大于或等于其子节点的值

  大根堆:既是大根树又是完全二叉树(增加了完全二叉树的限制条件)所以下图中只有(a)和(c)是大根堆

 1.2 大根堆的插入(数组实现)

  假设在下面大根堆中插入一个元素9,插入步骤如下,时间复杂度为O(height)=O(logn)

  • 尝试插入在6号位置,如果新的元素小于3号位置,则插入;否则把3号位置的元素向下移动到6号位置
  • 尝试插入在3号位置,如果新的元素小于1号元素,则插入;否则把1号位置的元素向下移动到3号位置,循环终止

1.3 大根堆的出队

  出队元素是最大的元素,也就是根节点,我们首先将1号元素删除,然后拿到最后一个元素,从上向下做插入的操作,时间复杂度为O(height)=O(logn)

1.4 大根堆的初始化

  自下而上:从最后一个元素开始对比,到第一个元素结束,具体步骤如下

  • ①找到孩子节点 2 和 7 中更大的元素,接下来与其双亲节点对比,7 更大所以交换 5 和 7 的位置
  • ①找到孩子节点 7 和 6 中更大的元素,接下来与其双亲节点对比,7 更大所以交换 1 和 7 的位置;②找到孩子节点 2 和 5 中更大的元素,接下来与其双亲节点对比,5 更大所以交换 1 和 5 的位置

  这里的循环包括两个步骤,第一个步骤是从下到上交换一次,第二个步骤是从上到下再检查一遍

2.左高树

2.1 高度优先左高树和重量优先左高树

  左高树合并操作的时间复杂度更低,适合需要合并操作较多的数据

  定义一类特殊的节点为外部节点来代替空子树,其余节点为内部节点。增加了外部节点的二叉树称为扩充二叉树

  定义距离s:s 是该节点到外部节点的最短路径

  定义重量w:w 是该节点重量的和,节点本身重量为1,节点的重量为自身重量与孩子重量的和。

  高度优先左高树(height-biased leftist tree,HBLT):这个二叉树任何一个内部节点左孩子的 s 值都大于等于右孩子的 s 值。其中上图(a)就不是一棵左高树,因为它左侧子树的左孩子值为0,而右孩子值为1,下图是2个HBLT。

  重量优先左高树(weight-biased leftist tree,WBLT):这个二叉树任何一个内部节点左孩子的 w 值都大于或等于右孩子的 w 值。

2.2 HBLT的性质

  1. 堆的性质:任意节点值的大小 ≤ 其孩子节点的大小(小根堆,也可以是 ≥ )
  2. 左偏性质:左孩子的距离 s ≥ 右孩子的距离 s 
  3. 任意节点的距离 s 都等于其右孩子的距离 + 1
  4. 一棵有 n 个节点的二叉树,根的距离dis ≤ long(n+1) - 1(距离最远就是满二叉树的情况,否则一定有更短路径出去)

2.3 HBLT的插入和删除

  插入相当于将已有的树和一棵仅有一个元素的树进行合并操作

  删除相当于将左右两棵HBLT进行合并操作

2.4 HBLT的合并(链式实现)

   用一张图解释合并的过程,我们需要把两棵树合并到 x 上

  • 对比 x 指向节点数值和 y 指向节点数值的大小
  • 如果节点数值 x < y,则将 x 指向的地址和 y 指向的地址交换
  • 将 x 指针移动到 x 的右孩子位置

  这就是图左完整的递归过程,递归的过程实际上就是在比较两个左高树右侧孩子链的大小,并来回交换来保证堆的性质,所以整个递归应该是O(logm)+O(logn)的时间复杂度

  • 首先 x 移动到下一个位置指向元素 7,对比元素 7 和元素 8,元素 8 更大,所以指针指向的地址互换,元素 8 移动到右孩子的位置
  • 然后 x 移动到下一个位置指向元素 6,对比元素 6 和元素 7,元素 7 更大,所以指针指向的地址呼唤,元素 7 移动到右孩子的位置
  • 然后 x 移动到下一个位置指向 NULL,因为 x 指向 NULL,所以直接将 x 指向 y 所指向的地址,递归结束

  最后一步是回溯,已经完成元素的插入后,需要维护左高树的性质,回溯的过程就是根据距离不断交换孩子节点的位置,保证左孩子的距离 ≥ 右孩子的距离

猜你喜欢

转载自blog.csdn.net/MeTicals/article/details/133900725