STL之heap的make_heap函数

来源:互联网 发布:绅士之庭邀请码 淘宝 编辑:程序博客网 时间:2024/06/07 07:46

在看侯捷翻译的STL源码剖析时,发现关于heap这一节点错误,特此指出.


1 make_heap源码

template <class _RandomAccessIterator>inline void make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last){  __make_heap(__first, __last,              __VALUE_TYPE(__first), __DISTANCE_TYPE(__first));}

make_heap用的是__make_heap函数.


2 __make_heap源码

template <class _RandomAccessIterator, class _Tp, class _Distance>void __make_heap(_RandomAccessIterator __first,            _RandomAccessIterator __last, _Tp*, _Distance*){  if (__last - __first < 2) return;  _Distance __len = __last - __first;  _Distance __parent = (__len - 2)/2;      while (true) {    __adjust_heap(__first, __parent, __len, _Tp(*(__first + __parent)));    if (__parent == 0) return;    __parent--;  }}

这是建heap的标准过此,即从(n-1)/2 到 0, 调用__adjust_heap进行最大堆性质的保持.注: n为最后一个元素的下标(0 , 1, ... n).


3 __adjust_heap源码

template <class _RandomAccessIterator, class _Distance, class _Tp>void __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,              _Distance __len, _Tp __value){  _Distance __topIndex = __holeIndex;  _Distance __secondChild = 2 * __holeIndex + 2;  while (__secondChild < __len) {    if (*(__first + __secondChild) < *(__first + (__secondChild - 1)))      __secondChild--;    *(__first + __holeIndex) = *(__first + __secondChild);    __holeIndex = __secondChild;    __secondChild = 2 * (__secondChild + 1);  }  if (__secondChild == __len) {    *(__first + __holeIndex) = *(__first + (__secondChild - 1));    __holeIndex = __secondChild - 1;  }  __push_heap(__first, __holeIndex, __topIndex, __value);}

这个函数比较关键,与我们常写的的方法不太一样.假设当前节点为p, 通常的方法是: 

  1. 找到p的左右孩子(如果有)中最大值m
  2. 若p的值大于m,没有破坏最大堆性质,直接退出.
  3. 若p的值小于m, 则交互p与最大的孩子的值,同时p指向交换的孩子,继续第一步.

而上面的__adjust_heap并没有父节点与最大孩子节点值的比较,而是直接给父节点赋值最大孩子的值,并下溯.

唯一的不同在于__adjust_heap调用了__push_heap函数.

然而侯捷指出:


可以将__push_heap改为*(first+holeIndex) = value;一下子然我蒙啦,想了许久都没想通.

4 __push_heap源码

template <class _RandomAccessIterator, class _Distance, class _Tp>void __push_heap(_RandomAccessIterator __first,            _Distance __holeIndex, _Distance __topIndex, _Tp __value){  _Distance __parent = (__holeIndex - 1) / 2;  while (__holeIndex > __topIndex && *(__first + __parent) < __value) {    *(__first + __holeIndex) = *(__first + __parent);    __holeIndex = __parent;    __parent = (__holeIndex - 1) / 2;  }      *(__first + __holeIndex) = __value;}

__push_heap相当于在堆中插入一个元素.即对空洞位置的调整.不过,为什么追求高效的STL要这么写呢?

如果对一个已是最大堆的堆再调用make_heap,举例:

最大堆: [3, 2, 1]

按STL的实现将会这样执行

1) 将父节点值3保存到变量value中,这样父节点将变成空洞节点记为p.   [ p, 2, 1]

2) 找孩子节点的最大值,赋值给空洞节点p = 2,空洞节点p下溯到左孩子. [2, p, 1]

3) 再次计算左右孩子位子,超出范围,调用__push_heap函数,

4) 调整p的位置,又将2回归到原来位置, 退出while循环.[p, 2, 1]

5) 将value赋值到空洞节点. [3, 2, 1],完成.


本人觉得,还不如直接按照常规方法,在adjust_heap比较父节点和最大孩子节点的值.这样效率更高.

至于STL为什么这么写,如果有读者知道,请给我留言.






1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 高等继续教育网打不开课程怎么办 安运继续教育的登录密码忘了怎么办 金蝶k3账套管理打不开了怎么办 仁和会计课堂app不能用怎么办 光大银行已经下卡了终审被拒怎么办 过了上诉期和申诉期该怎么办 北外大四学生要实习半年课程怎么办 电脑发给手机的文件过期了怎么办 农民给土地卖了30年后怎么办 家长发家长群作业太多老师怎么办 在考试中心补不了四级成绩怎么办 微信登录密码不记得了怎么办 欠农民工工资不给怎么办老板说没钱 国外期刊催问稿件不理睬怎么办 老公离不开老婆也离不开小三怎么办 出轨被老婆发现还和小三联系怎么办 老公出轨后回家老婆不想原谅怎么办 小三和原配打架都住院了怎么办 毕业太多年查不到学历认证怎么办 没有做税种核定开了票怎么办 在学信网上查不到学历信息怎么办 学信网手机号换了密码忘了怎么办 学信网手机号换了密码也忘了怎么办 学信网上学习形式是星号怎么办 新手机号已被注册微店买家怎么办 微信号被冻结了里面的钱怎么办 不懂公司产品却要接待老外怎么办 上菜时发现桌面摆不下新菜怎么办 超市买到过期产品商家不赔尝怎么办 皇帝成长计划2俘虏的士兵怎么办 晚上楼上有挪桌子的声音怎么办 金灶茶具出故障码e7怎么办 起亚k2灯泡掉进大灯总成怎么办 衣服上拆过线的针孔怎么办 驾考科目二坡道定点熄火怎么办 穿着超短裤感觉要漏屁股怎么办 台式电脑开机后无法进入系统怎么办 产后两年了肚子肥胖松弛怎么办 在作文中写上自己的名字怎么办 外出玩耍时迷路了你会怎么办 外出玩耍时孩子总喜欢乱跑怎么办?