阿龙的学习笔记---《Effective STL》读书笔记(三)

条款22:避免原地修改set和multiset的键
  • 正如所有标准关联容器,set和multiset保持它们的元素有序,这些容器的正确行为
    依赖于它们保持有序。 如果你改了关联容器里的一个元素的值(例如,把10变为1000),新值可能不在正确
    的位置。
  • 正确做法:找到想要修改的元素,做一份拷贝,修改拷贝值,删除原来元素,添加修改后的新元素。
    这样,重新插入的时候还会进行新的排序。

条款23:考虑用排序的vector代替关联容器
  • vector比起关联容器,效率高很多。
  • 这适用于当你最开始初始化vector之后不怎么进行插入删除等操作(因为很费时),并且又会用到二分查找等算法,排序vector查找效率也是log2n。

条款24: 考虑map::operator[]和map-insert之间的效率
  • 当你添加操作时,用map::operator[],需要创建对象,返回引用等操作。
  • 而insert则效率更高。
  • 而当你更新已经在表中的值时,map::operator[] 更加高效。

条款25::熟悉非标准散列容器
  • 有以散列形式的:hash_set、hash_multiset、hash_map和hash_multimap
  • 新的C++中有了是unordered_set、unordered_multiset、unordered_map和unordered_multimap。

条款26:尽量用iterator代替const_iterator,reverse_iterator和const_reverse_iterator
  • iterator的作用相当于T*,而const_iterator则相当于const T*。
  • 尽量使用iterator会让程序更加兼容性,避免潜在问题。

条款27:把const_iterator转化成iterator
  • 不能直接转换,编译器不支持。
  • 可以指向相同位置。
  • 这个任务得到了两个函数模板advance和distance的帮助,它们都在<iterator>中声明。distance返回两个指向同一个容器的iterator之间的距离;advance则用于将一个iterator移动指定的距离。
    IntDeque d;
    ConstIter ci;
    Iter i(d.begin()); // 初始化i为d.begin()
    advance(i, distance(i, ci)); // 把i移到指向ci位置
    

条款28:了解如何通过reverse_iterator的base得到iterator

在这里插入图片描述

  • ri.base() 与 ri 在insert中等价。要实现在一个reverse_iterator ri指出的位置上插入新元素,在ri.base()指向的位置插入就行了。而删除则不等价。

条款29:需要一个一个字符输入时考虑使用istreambuf_iterator

条款30: 确保目标区间足够大
  • transform算法是将元素经一个操作,放入另一个位置。如果你是要加到一个容器的末尾,那么需要使用insertor-插入型迭代器来创建。
vector<int> values; 
vector<int> results;
transform(values.begin(), values.end(), // 把transmogrify的结果
	back_inserter(results), // 写入results的结尾,
 	transmogrify); // 处理时避免了重新分配
  • 这里如果用results.end(),那是个没有元素的值,运行会失败。
  • 但假如result的本身的元素个数多于values,那么你可以使用result.begin()来替换元素,这里就不是插入了,而是替换。如果需要在前面插入,可以用front_insertor。

条款31:了解各种排序的算法选择
  • sort用于排序。
  • partial_sort 是部分排序,将前20个以自定义的比较函数排在前面:
    partial_sort(widgets.begin(), // 把最好的20个元素
     	widgets.begin() + 20, // (按顺序)放在widgets的前端
     	widgets.end(),
     	qualityCompare);
    
  • nth_element排序一个区间,在ri位置(你指定的)的元素是如果区间被完全排序后会出现在那儿的元素。另外,当nth_element返回时,在n以上的元素没有在排序顺序上在位置n的元素之后的,而且在n以下的元素没有在排序顺序上在位置n的元素之前的。
    可以将前20个放在前面,但是是无序的。
  • 但是上面的都是不稳定的,稳定的排序是stable_sort。
  • partition算法,它重排区间中的元素以使所有满足某个标准的元素都在区间的开头。(快排中的操作)。以及还有稳定的stable_partition。

条款32:删除元素需要在remove后再用成员函数erase

条款33:对于含有指针的容器,注意remove操作
  • remove操作可能会在你准备delete前,先把指针销毁了,导致内存泄漏。因为remove操作中默认你的这些元素以及没用了,有些会放到尾部,有些可能就没了。

条款34:注意有些算法需要排序区间
  • 搜索算法binary_search、lower_bound、upper_bound和equal_range(参见条款45)需要有序区间,因为它们使用二分法查找来搜索值。
  • 还有一些不常用的。

条款35:一种方式实现忽略大小写的字符串比较方法
  • 通过mismatch或lexicographical实现。

条款36:了解copy_if的正确实现

条款37:用accumulate或for_each来统计区间
  • 对区间元素进行统计,比如求平均,求和等,可以使用上述两种方法。

  • accumulate存在两种形式。带有一对迭代器和初始值的形式可以返回初始值加由迭代器划分出的区间中值的和:

    list<double> ld; // 建立一个list,放一些double进去
    double sum = accumulate(ld.begin(), Id.end(), 0.0); // 计算它们的和,
    

    另一种是带有一个初始和值与一个任意的统计函数,这变得一般很多。


条款38:按照传值的原则来设计函数对象子类
  • 无法直接传递函数,可以传递函数指针。
  • STL函数对象是函数指针的一种抽象和建模形式。而传入for_each函数等操作,是传值的方式传递这个函数对象。
  • 所以函数对象尽量小,让传值效率高。还有一个多态方面的没细看。

条款39:用纯函数做判断式
  • 判别式是返回bool的。纯函数是返回值只依赖于参数的函数。如果f是一个纯函数,x和y是对象,f(x, y)的返回值仅当x或y的值改变的时候才会改变。
  • 如果不是,可能一些算法的结果会出乎你的预期。

条款40,41:不懂

条款42:确定less 与 operator< 有相同含义
  • 默认的less通过调用Widget的operator<来工作。
  • 违背不太好,会带来问题。

条款43:尽量用算法调用代替手写循环
  • 有三个理由:
    • 效率:算法通常比程序员产生的循环更高效。
    • 正确性:写循环时比调用算法更容易产生错误。
    • 可维护性:算法通常使代码比相应的显式循环更干净、更直观。

条款44:尽量用成员函数代替同名的算法
  • 有些容器拥有和STL算法同名的成员函数。
    • 关联容器提供了count、find、lower_bound、upper_bound和equal_range,
    • 而list提供了remove、remove_if、unique、sort、merge和reverse。
  • 大多数情况下,你应该用成员函代替算法。这样做有两个理由。
    • 首先,成员函数更快。
    • 其次,比起算法来,它们与容器结合得更好

条款45: 注意count、find、binary_search、lower_bound、upper_bound和equal_range的区别
  • 选择合适的最重要、

条款46: 考虑使用 函数对象 代替 函数指针 作STL算法的参数
  • 现把STL函数对象——化装成函数的对象——传递给算法所产生的代码一般比传递真的函数高效。

  • 这个行为的解释很简单:内联。


条款47: 避免产生直写代码
  • 太多的嵌套不好。

条款48:总是#include适当的头文件

条款49,50:没啥用

完结撒花。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值