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

         改写adjust_heap函数,让要插入值与插入点的孩子节点进行比较判断。
template < class Distance,class Tp, class Compare>
inline void adjust_heap( Tp *first, Distance holeIndex, Distance len, Distance distIndex,Tp val,Compare cmp)
{
*(first +distIndex) = *(first+holeIndex); //将根节点写入要交换处

int secondChild = 2 *( holeIndex + 1); //holeIndex 节点的右子节点
while (secondChild < len) //二叉树的节点个数
{
//右节点大于左节点
if ( cmp( *(first + secondChild) ,*(first + secondChild - 1 ) ) )
{
--secondChild; //选择较小的左节点
}
//左节点大于等于Val,则插入并返回
if ( *(first + secondChild) >= val ){ *(first + holeIndex)=val; return;}
*(first + holeIndex) = *(first + secondChild); //holeIndex 节点写为较大子节点
holeIndex = secondChild; //holeIndex设为较大子节点的索引,继续循环
secondChild=2*(secondChild+1);
}
//holeIndex节点没有右子节点并且左子节点大于Val
//左子节点上移,Val写入左子节点的位置
if (secondChild == len && cmp( val, *(first+secondChild-1) ) )
{
*(first+holeIndex)=*(first+secondChild-1);
*(first+secondChild-1)=val;
}
//否则holeIndex写为Val
else *(first + holeIndex)=val;
}
程序就变为:solution_2
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])
{
adjust_heap(BigArr,0,(int)RES_ARR_SIZE,j,*(BigArr+j)
,greater<int>( ) ); );
}
}
      用 (int)RES_ARR_SIZE,是因为RES_ARR_SIZE定义为const unsigned int ,所以要强制转换下。
随机情况下solution_2为483 毫秒左右比solution_1快了10%,数组有序情况下为38秒左右,比solution_1快了80%。
没有出现是solution_1速度3倍的原因,我分析了下,


1. 在随机乱序情况下,一次完整遍历要300毫秒左右,所以没多大差别。
2. 在数组完全有序(由小到大)时,在adjust_heap未调用push_heap时用时O(logm),调用的push_heap根本就没有递归深入到根节点处。在pop_heap和push_heap一段时间后,每层元素乱序但每个元素都大于下一层的元素。push_heap从来就没有递归到根节点!但模板实例化和函数嵌套调用耗了大量的时间。


我再将模板具体实例化solution_3
inline void adjust_heap(int * first, int holeIndex, int len, int distIndex,int val)
{
*(first +distIndex) = *(first+holeIndex);//将根节点写入要交换处
int secondChild = 2 *( holeIndex + 1);//holeIndex 节点的右子节点
while (secondChild < len)//二叉树的节点个数
{
//右节点大于左节点
if (*(first + secondChild) > *(first + (secondChild - 1)))
{
--secondChild; //选择较小的左节点
}
//左节点大于等于Val,则插入并返回
if ( *(first + secondChild) >= val ){ *(first + holeIndex)=val; return;}

*(first + holeIndex) = *(first + secondChild);//holeIndex 节点写为较大子节点
holeIndex = secondChild;//holeIndex设为较大子节点的索引,继续循环
secondChild=2*(secondChild+1);
}
//holeIndex节点没有右子节点并且左子节点大于Val
//左子节点上移,Val写入左子节点的位置
if (secondChild == len && *(first+secondChild-1) < val)
{
*(first+holeIndex)=*(first+secondChild-1);
*(first+secondChild-1)=val;
}
//否则holeIndex写为Val
else *(first + holeIndex)=val;
}

 程序中调用

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])
            {
                adjust_heap(BigArr,0,(int)RES_ARR_SIZE,j,*(BigArr+j));
            }
           
        }


     测试了下,随机情况时间为480毫秒左右,数组从小到大有序时为18.8秒,比solution_1快了近3倍。综合solution_1,solution_2,看来在大量需要重复执行的地方,运行时模板实例化和函数嵌套调用的耗时不可小觑,呵呵

 

总结:

1.STL的确是个好东西,又快又安全又方便。

2.在函数反复调用的地方,如果要考虑效率,则应慎重些。


     以上均是个人主观遐想,欢迎拍砖。


程序下载:http://download.csdn.net/source/2148538
参考资料:
1. 赖勇浩《从一道笔试题谈算法优化》
http://blog.csdn.net/lanphaday/archive/2008/12/18/3547776.aspx
2.Sartaj Sahni《数据机构、算法与应用---C++语言描述》
3. 叶至军《C++ STL开发技术导引》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值