【C++】STL常用容器总结之四:链表list
2016-08-25 10:34
801 查看
5、链表list
List是每个节点包含前驱指针、后继指针和数据域三个部分的双向链表。List不提供随机存取,访问元素需要按顺序走到需存取的元素,时间复杂度为O(n),在list的任何位置上执行插入或删除操作都非常迅速,只需在list内部调整一下指针。list不仅是一个双向链表,而且还是一个环状双向链表。所以它只需要一个指针,便可以完整实现整个链表。(这里需要特别强调一下:list到底是不是双向链表?有的书上说是,有的书上没说,所以大家注意一下,这里暂把list当作双向链表,等博主找到资料再做解释)与向量vector相比,list允许快速的插入和删除,且每次插入或删除一个元素,就配置或释放一个元素空间,对于任何位置的元素插入或元素移除,list永远是常数时间。
List不再能够像vector那样以普通指针作为迭代器,因为其节点不保证在储存空间中连续存在。list迭代器必须有能力指向list的节点,并有能力进行正确的递增、递减、取值、成员存取等操作。所谓list迭代器正确的递增、递减、取值、成员取用操作是指,递增时指向下一个节点,递减时指向上一个节点,取值时取的是节点的数据值,成员取用时取用的是节点的成员。
List有一个重要性质:插入操作(insert)和合并操作(splice)都不会造成原有的list迭代器失效。这在vector是不成立的,因为vector的插入操作可能造成记忆体重新配置,导致原有的迭代器全部失效。甚至list的元素删除操作(erase)也只有“指向被删除元素”的那个迭代器失效,其他迭代器不受任何影响。
在使用list类模版时,也必须包含相应的头文件:
#include<list>,list对象的声明与vector类似,这里仅仅介绍一下list的成员函数。
1、声明list容器
list list1; // 声明一个空的list1list list2 (4, 100); // 声明以个含4个100的list2
list list3 (list2.begin(), list2.end()); // 用list2的迭代器内容声明list3
list list4 (list3); // 声明list4为list3的一个副本
list list5(size); // 声明一个含size个默认值为0的list5
list1.~list(); // 注销list
2、list与vector不相同的一些操作
List与vector相同的一些操作,这里仅列出函数名,不再进行具体说明:Begin/end/rbegin/rend/empty/size/Max_size/resize/insert/erase/swap/clear。以下这些函数是list与vector不同的函数:
list<int> list1;
1、访问list元素
list1.front():返回第一个元素的值。list1.back():返回最后一个元素的值。
2、list元素的插入与删除
list1.push_front(x):把元素x插入到链表头部。list1.pop_front():删除第一个元素。
list1.push_back(x):把元素x插入到链表尾部。
list1.pop_back():删除最后一个元素。
list1.remove(val):删除链表中所有值为val的元素。
list1.remove_if(pred):删除链表中谓词pred为真的元素(谓词即为元素存储和检索的描述,如std::less<>,std::greater<>那么就按降序/升序排列,你也可以定义自己的谓词)。
list1.unique():删除链表中所有重复的元素(这个函数博主在VS上测试的时候,并没有删除所有重复的元素,大家使用的时候最好也亲测一下。。。)。
list1.unique(pred):根据谓词pred删除所有重复的元素,使链表中没有重复元素。
3、list拼接操作
splice():链表拼接,参数position是迭代器而不是下标。list1.splice ( position, list2 ):将list2中的所有元素插入到list1中position处,list2会被清空,position仍然指向list1中的那个元素。
list1.splice ( position, list2, iter ):将list2中iter处的元素插入到list1中position处,list2会将iter指向的元素删除,iter失效。
list1.splice ( position, list2, first, last ):将list2中[first,last)位置处的元素插入到list1的position处。
4、list合并操作
merge(listref):链表合并:把listref所引用的链表中的所有元素插入到链表中,可指定合并规则。OutputIterator merge (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result);
OutputIterator merge (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp); // 由于参数复杂,这里列出了C++官网给出的原函数,具体的例子可以参考C++官网.
5、list排序操作
sort():根据默认的谓词对链表排序,默认升序。sort(pred):根据给定的谓词对链表排序。
3、vector与list之间的区别
C++标准库中,容器vector和list都可以用来存放一组类型相同的数据。而且二者不同于数组的一点是,支持动态增长。但它们还是有几点不同:1. Vector是顺序表,表示的是一块连续的内存,元素被顺序存储;list是双向链表,在内存中不一定连续。
2. 当数值内存不够时,vector会重新申请一块足够大的连续内存,把原来的数据拷贝到新的内存里面,再释放旧空间;list因为不用考虑内存的连续,因此新增开销比vector小。
3. List只能通过指针访问元素,随机访问元素的效率特别低,在需要频繁随机存取元素时,使用vector更加合适。
4. 当向vector插入或者删除一个元素时,需要复制移动待插入元素右边的所有元素;因此在有频繁插入删除操作时,使用list更加合适。
5. Vector和deque支持随机访问,而list不支持随机访问,因此list不支持[ ]访问。
相关文章推荐
- 【C++】STL常用容器总结之九:集合set
- C++STL之list双向链表容器
- 浅谈STL list<T>链表容器和迭代器的使用C++实现
- 【C++】STL常用容器总结之十二:string类
- 【C++】STL常用容器总结之五:双端队列deque
- C++ STL 容器部分有关list 链表容器的基本操作
- 【C++】STL常用容器总结之三:向量vector
- C++ STL学习笔记四 list双向链表容器
- 【C++】STL常用容器总结之十:多重映射multimap和多重集合multiset
- 【C++】STL常用容器总结之二:顺序容器
- 【C++】STL常用容器总结之六:基于deque的顺序容器适配器
- C++ STL 容器技术 之 list双向链表容器
- C++ STL 容器技术 之 list双向链表容器
- C/C++STL常用容器用法总结
- [C++ 从入门到放弃-07]C++STL之list双向链表容器
- 【C++】STL常用容器总结之十一:容器小结
- 【C++】STL常用容器总结之七:对组pair与关联容器
- 【C++】STL常用容器总结之八:映射map
- C++ STL学习笔记四 list双向链表容器
- 【C++】STL常用容器总结之一:容器与迭代器