目录
1.emplace、emplace_back、emplace_front
2.sort(有了算法库的sort,为什么要提供成员函数sort?)
杂谈
和vector一样,list也是一个类模板。第一个模板参数T表示list用于存什么类型的数据,第二个模板参数表示内存池类。
有人可能认为在刷题时似乎很少用到list,进而认为list不常用,实际上这是一种短视的看法,刷题时用得多只是因为测试用例都是以数组的形式给的,而在实际工作中,list是很常用的一种容器,因为vector有优点的同时也有许多缺点,比如vector在频繁头插或者头删的场景下效率十分低下,此时就不该用vector,而可以试试list。
构造函数
1.第一种表示默认构造,因为内存池对象可以不传,所以可以认为是无参的。
2.用n个val构造list,老熟人了。
3.利用迭代器区间构造list,不包括last指向的元素,因此区间为左闭右开【first,last) 。
4.拷贝构造。
容量相关函数
可以肉眼观察到 list的容量相关函数对比vector和string少了许多,这是因为list不涉及到扩容相关的问题,list只用按需申请即可。
1.empy
用于判断list是否为空,即是否存储了有效数据。
2.size
用于返回list中存储的有效数据的个数,返回类型为size_t。
修改函数
1.emplace、emplace_back、emplace_front
这边涉及到右值引用,暂且留到C++11讲解,只需知道这三个接口的功能分别对应insert、push_back、push_front。
2.对比vector修改函数的区别
可以发现list没有提供operator【】()接口,不支持随机访问。
2.assign
用于给list赋值。
3.insert(迭代器失效?)
可以发现使用方式和vector的insert没有什么不同。注意,因为list不需要扩容,因此不管怎么insert,list中的迭代器都不会失效。
1.在迭代器position指向的位置上插入T类型的val。
2.在迭代器position指向的位置上插入n个val。
3.在迭代器position指向的位置上插入一段迭代器区间的值。
4.erase(迭代器失效?)
1.删除迭代器position指向位置上的元素。
2.删除迭代器区间【first,last)上所有的元素,注意不包括last指向的元素。
erase函数是有返回值的,erase一个元素后会返回指向该元素的下一个元素的迭代器。
如下图演示能够证明erase是存在迭代器失效的,这里也很好理解,毕竟erase一个节点后,这个节点肯定是要被delete从堆上释放的,但注意此时迭代器还指向被删除节点的空间,再次通过迭代器去访问节点就是经典的野指针问题了。
5.clear
用于清空链表。
6.swap
用于交换链表管理的数据。
操作函数
1.可以发现和vector一样,都没有提供find接口。
list和vector与string不同,他俩都没有提供find接口。这是因为所有容器都有迭代器,所以find可以实现成一个函数模板,这样find就可以通过迭代器在任意容器里寻找指定元素,此时vector或者list再提供一个find成员函数就多此一举了。而string类和它们不太一样,因为在string中查找时,可能找一个字符,可能找一个字串,找到后返回下标。因为string的查找具有多样性,从而导致了string的查找比较独特,所以STL认为有必要单独为string实现一个find接口。
对于算法库中的find,如果找到了目标元素,则返回指向目标元素的迭代器;反之返回指向最后一个元素后一个位置的迭代器,即相当于container.end()。
2.sort(有了算法库的sort,为什么要提供成员函数sort?)
用于给list中的元素排序,默认是排升序。模板参数Compare必须是一种可调用对象的类型,comp则必须是一种可调用对象,比如函数对象(即仿函数)、函数指针、函数等,如果想排降序,则给comp传一个逻辑为排降序的可调用对象。
这里有一个问题:明明<algorithm>中已经有一个sort了,为什么list要多此一举提供一个成员函数sort呢?
答案:因为list用不了算法库中的sort。如下图,可以观察到算法库中的sort是通过随机存取迭代器排序的,而list的物理空间不是连续的,因此list的迭代器不是随机存取迭代器,所以list用不了算法库里的sort,为此STL给list单独设计了成员函数sort。
3.merge
用于将两条list合并再排序,如下图演示,ls1合并ls2后,因为ls1调用的该接口,因此ls2被清空了。
4.reverse
用于逆置list中的元素。
5.unique
用于删除list中的重复值,即去重,如下图演示。
注意unique去重是对数据有要求的,要求数据必须有序,因此使用unique前必须调用sort成员函数排序。也正是因为要排序,导致unique接口不常用,因为list排序的代价较大。去重我们可以用未来要学习的set容器,只需要将所有数据往set里插入,它天然支持去重。
6.splice
用于将链表A的全部或者某一部分转移到另一条链表B上,注意链表A的节点被转移是真正意义上的转移了,如下图演示,将整个ls2转移到ls1后,ls2这条链表就是一条空链表了。
接口1:将链表x整体移到迭代器position指向的另一条链表上。
接口2:将迭代器i指向的位于链表x上的单个节点转移到迭代器position指向的另一条链表上。
接口3:将链表的一个迭代器区间上的所有节点转移到迭代器position指向的另一条链表上。
7.remove
用于删除链表中所有值等于val的节点,这个接口本质就是先find然后erase的多次循环。
8.remove_if
也是用于删除链表中的节点,只不过这里可以自定义删除的条件,比如大于10就删除等等。这里的模板参数Predicate必须是一种可调用对象的类型,pred也必须是一种可调用对象,比如函数对象(即仿函数),函数指针,函数等等,如下图所示。