也论从1亿个整数中找出最大的1万个(上)

                                                               不成熟的优化是万恶之源。--Donald Knuth (引用Hoare的话)
                                                                                     另一方面,我们不能忽视效率。--Jon Bentley
     受赖勇浩《从一道笔试题谈算法优化》启发,我想如果建堆,利用堆插入删除都是O(logn),速度是不是更快一点。于是我建了一个含1万个元素的最小堆,然后遍历整个数组。如果有大于堆根节点的元素,就交换,并整理堆。
      假设和1亿(n)和1万(m)都是可以改变的数,则算法时间复杂度O(n*logm)。
solution_1:
const unsigned int BIG_ARR_SIZE = 100000000;//一亿
const unsigned int RES_ARR_SIZE = 10000;

make_heap(BigArr,BigArr+RES_ARR_SIZE,greater_equal<int>());
for(int j=RES_ARR_SIZE;j<BIG_ARR_SIZE;j++) {
//大于最小堆根节点,岀堆,交换值,再入堆 If(BigArr[0]<BigArr[j]) { pop_heap(BigArr,BigArr+RES_ARR_SIZE,greater_equal<int>()); swap(BigArr[RES_ARR_SIZE-1],BigArr[j]); push_heap(BigArr,BigArr+RES_ARR_SIZE,greater_equal<int>());
}}
1. 在STL中pop_heap函数只是把根节点交换到last的位置,根节点并未被删除(erase)
2. 所以交换last处和j处的元素,这样就把需要插入的元素放在了堆的最后面
3. 再push_heap,push_heap函数是把堆之后的一个元素就是我们要插入的元素压入堆中
测试了下,在随机情况下,大概要531毫秒,。在极端情况即数组由小到大排序时,大概要61秒。
我又看了下 STLport 的pop_heap函数(原谅我,VC STL源码的可读性实在太差)。
__pop_heap_aux(_RandomAccessIterator __first,
_RandomAccessIterator __last, _Tp*, _Compare __comp)
{
__pop_heap(__first, __last - 1, __last - 1, _Tp(*(__last - 1)), __comp,
_STLP_DISTANCE_TYPE(__first, _RandomAccessIterator));
}
__pop_heap_aux 调用__pop_heap函数
void__pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
_RandomAccessIterator __result, _Tp __val, _Compare __comp,
_Distance*)
{
*__result = *__first; //将根节点移到堆的末尾
__adjust_heap(__first, _Distance(0), _Distance(__last - __first),
__val, __comp);
}
__pop_heap再接着调用__adjust_heap函数
void __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
_Distance __len, _Tp __val, _Compare __comp)
{
_Distance __topIndex = __holeIndex;
_Distance __secondChild = 2 * __holeIndex + 2;
while (__secondChild < __len) {
if (__comp(*(__first + __secondChild), *(__first + (__secondChild - 1)))) {
_STLP_VERBOSE_ASSERT(!__comp(*(__first + (__secondChild - 1)), *(__first + __secondChild)),
_StlMsg_INVALID_STRICT_WEAK_PREDICATE)
__secondChild--;
}
*(__first + __holeIndex) = *(__first + __secondChild);
__holeIndex = __secondChild;
__secondChild = 2 * (__secondChild + 1);
}
if (__secondChild == __len) {
*(__first + __holeIndex) = *(__first + (__secondChild - 1));
__holeIndex = __secondChild - 1;
}
//__adjust_heap再调用__push_heap函数
__push_heap(__first, __holeIndex, __topIndex, __val, __comp);
}


  发现没有,pop_heap 函数调用adjust_heap函数,最后adjust_heap函数又调用push_heap函数。
整个过程实际用了3*O(logm)(原谅我不规范的表达)的时间,如果一开始就让adjust_heap中的
左右节点和要交换的值比较来插入,时间复杂度就只有O(logm)。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值