您的位置:首页 > 编程语言 > C语言/C++

【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; // 声明一个空的list1

list 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 list