zoukankan      html  css  js  c++  java
  • 条款44:尽量用成员函数代替同名的算法

    有些容器拥有和STL算法同名的成员函数。关联容器提供了count、find、lower_bound、upper_bound和
    equal_range,而list提供了remove、remove_if、unique、sort、merge和reverse。大多数情况下,你应该用成员函
    数代替算法。这样做有两个理由。首先,成员函数更快。其次,比起算法来,它们与容器结合得更好(尤其
    是关联容器)。那是因为同名的算法和成员函数通常并不是是一样的。
    我们以对关联容器的实验开始。假如有一个set<int>,它容纳了一百万个元素,而你想找到元素727的第一个
    出现位置(如果存在的话)。这儿有两个最自然的方法来执行搜索:
    set<int> s; // 建立set,放入1,000,000个数据
    ...
    set<int>::iterator i = s.find(727); // 使用find成员函数
    if (i != s.end()) ...
    set<int>::iterator i = find(s.begin(), s.end(), 727); // 使用find算法
    if (i != s.end()) ...
    find成员函数运行花费对数时间,所以不管727是否存在于此set中,set::find只需执行不超过40次比较来查找
    它,而一般只需要大约20次。相反,find算法运行花费线性时间,所以如果727不在此set中,它需要执行
    1,000,000次比较。即使727在此set中,也平均需要执行500,000次比较来找到它。效率得分如下:
    find成员:大约40(最坏的情况)至大约20(平均情况)
    find算法:1,000,000(最坏的情况)至500,000(平均情况)
    和高尔夫比赛一样,分值低的赢。正如你所见,这场比赛结果没什么可说的。
    我必须对find成员函数所需的比较次数表示小小的谨慎,因为它有些依赖于关联容器的实现。绝大部分的实
    现是使用的红黑树——平衡树的一种——失衡度可能达到2。在这样的实现中,对一百万个元素的set进行搜
    索所需最多的比较次数是38次。但对绝大部分的搜索情况而言,只需要不超过22次。一个基于完全平衡树的
    实现绝不需要超过21次比较,但在实践中,完全平衡树的效率总的来说不如红黑树。这就是为什么大多数的
    STL实现都使用红黑树。
    条款44:尽量用成员函数代替同名的算法
    效率不是find成员函数和find算法间的唯一差别。正如条款19所解释的,STL算法判断两个对象是否相同的方
    法是检查的是它们是否相等,而关联容器是用等价来测试它们的“同一性”。 因此,find算法搜索727用的是
    相等,而find成员函数用的是等价。相等和等价间的区别可能造成成功搜索和不成功搜索的区别。比如说,
    条款19演示了用find算法在关联容器搜索失败而用find成员函数却搜索成功的情况!因此,如果使用关联容器
    的话,你应该尽量使用成员函数形式的find、count、lower_bound等等,而不是同名的算法,因为这些成员函
    数版本提供了和其它成员函数一致的行为。由于相等和等价间的差别,算法不能提供这样的一致行为。
    这一差别对map和multimap尤其明显,因为它们容纳的是对象对(pair object),而它们的成员函数只在意对
    象对的key部分。因此,count成员函数只统计key值匹配的对象对的数目(所谓“匹配”,自然是检测等价情
    况);对象对的value部份被忽略。成员函数find、lower_bound、upper_bound和equal_range也是如此。但是如
    果你使用count算法,它的寻找将基于(a)相等和(b)对象对的全部组成部分;算法find、lower_bound等同
    样如此。要想让算法只关注于对象对的key部分,必须要跳出条款23描述的限制(那儿介绍了用相等测试代替
    等价测试的方法)。
    另一方面,如果你真的关心效率,你可以采用条款23中的技巧,联合条款34中讲的对数时间搜索算法。相对
    于性能的提升,这只是一个很小的代价。再者,如果你真的在乎效率,你应该考虑非标准的散列容器(在条
    款25进行了描述),只是,你将再次面对相等和等价的区别。
    对于标准的关联容器,选择成员函数而不是同名的算法有几个好处。首先,你得到的是对数时间而不是线性
    时间的性能。其次,你判断两个元素“相同”使用的是等价,这是关联容器的默认定义。第三,当操纵map
    和multimap时,你可以自动地只处理key值而不是(key, value)对。这三点给了优先使用成员函数完美的铁甲。
    让我们转到list的与算法同名的成员函数身上。这里的故事几乎全部是关于效率的。每个被list作了特化的算法
    (remove、remove_if、unique、sort、merge和reverse)都要拷贝对象,而list的特别版本什么都没有拷贝;它们
    只是简单地操纵连接list的节点的指针。算法和成员函数的算法复杂度是相同的,但如果操纵指针比拷贝对象
    的代价小的话,list的版本应该提供更好的性能。
    牢牢记住这一点很重要:list成员函数的行为和它们的算法兄弟的行为经常不相同。正如条款32所解释的,如
    果你真的想从容器中清除对象的话,调用remove、remove_if和unique算法后,必须紧接着调用erase函数;但
    list的remove、remove_if和unique成员函数真的去掉了元素,后面不需要接着调用erase。
    在sort算法和list的sort成员函数间的一个重要区别是前者不能用于list。作为单纯的双向迭代器,list的迭代器不
    能传给sort算法。merge算法和list的merge成员函数之间也同样存在巨大差异。这个算法被限制为不能修改源
    范围,但list::merge总是修改它的宿主list。
    所以,你明白了吧。当面临着STL算法和同名的容器成员函数间进行选择时,你应该尽量使用成员函数。几
    乎可以肯定它更高效,而且它看起来也和容器的惯常行为集成得更好。
  • 相关阅读:
    标记场景发生改变
    粗体EditorGUI
    unity shader 编辑器扩展类 ShaderGUI
    让打开文件夹直接在某路径打开
    利用asset存储mesh
    获取输入的键
    2013 Visual Studio Magazine读者选择奖界面框架类获奖情况
    DevExpress VCL 13.1.4支持Delphi /C++Builder XE5
    DevExpress更新至13.1.7
    转:与Microsoft Visual Studio集成良好的第三方工具
  • 原文地址:https://www.cnblogs.com/lancidie/p/1983653.html
Copyright © 2011-2022 走看看