【C++初阶】List常用接口详解
文章目录
- 一、List的介绍
- 二、常用接口
- 2.1 构造函数
- 2.2 迭代器
- 2.3 insert
- 2.4 erase
- 2.5 reverse
- 2.6 sort
- 2.7 merge
- 2.8 unique
- 2.9 eplice
- 三、list与vector的对比
- 3.1 排序比较
- 3.2 vector 与 list 差异
- 文章结语
一、List的介绍
列表容器是以双链表的形式实现的;双链表能够将其所包含的每个元素存储在不同的且互不相关的存储位置中。其顺序是通过每个元素与其前一个元素和后一个元素之间的链接关系在内部保持的
list的文档介绍
二、常用接口
2.1 构造函数
2.2 迭代器
- 迭代器使用
begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动
intmain(){list<int>lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);list<int>::iterator it=lt.begin();while(it!=lt.end()){cout<<*it<<" ";it++;}for(autoe:lt){cout<<e<<" ";}return0;}- 迭代器失效
由于底层结构不同,各个容器有不同的迭代器
比如std::sort底层是快排,要求随机迭代器,不支持list容器
2.3 insert
因为迭代器不支持+、-,所以只能++/- -
intmain(){list<int>lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);intk=3;autoit=lt.begin();while(k--){it++;}lt.insert(it,100);for(autoe:lt){cout<<e<<" ";}return0;}2.4 erase
intmain(){list<int>lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);intk=3;autoit=lt.begin();intx;cin>>x;autotmp=find(it,lt.end(),x);lt.erase(tmp);for(autoe:lt){cout<<e<<" ";}return0;}2.5 reverse
intmain(){list<int>lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);lt.reverse();for(autoe:lt){cout<<e<<" ";}return0;}2.6 sort
intmain(){list<int>lt;lt.push_back(1);lt.push_back(5);lt.push_back(4);lt.push_back(0);lt.push_back(2);//lt.sort(greater<int>());lt.sort(less<int>());for(autoe:lt){cout<<e<<" ";}return0;}2.7 merge
合并会让一个链表为空
intmain(){list<int>lt1;list<int>lt2;lt1.push_back(1);lt1.push_back(5);lt1.push_back(4);lt1.push_back(0);lt1.push_back(2);lt2.push_back(6);lt2.push_back(4);lt2.push_back(3);lt2.push_back(2);lt2.push_back(10);lt1.sort();lt2.sort();lt1.merge(lt2);for(autoe:lt1){cout<<e<<" ";}return0;}2.8 unique
前提是有序的链表
intmain(){list<int>lt1;list<int>lt2;lt1.push_back(1);lt1.push_back(5);lt1.push_back(5);lt1.push_back(4);lt1.push_back(0);lt1.push_back(2);lt1.sort();lt1.unique();for(autoe:lt1){cout<<e<<" ";}return0;}2.9 eplice
intmain(){list<int>lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);lt1.push_back(4);lt1.push_back(5);lt1.push_back(6);autoit=lt1.begin();autoit1=find(it,lt1.end(),5);lt1.splice(it,lt1,it1,lt1.end());for(autoe:lt1){cout<<e<<" ";}return0;}三、list与vector的对比
3.1 排序比较
intmain(){srand((unsignedint)time(NULL));intn=1000000;list<int>lt1;vector<int>v;for(inti=0;i<n;i++){autoe=rand()+i;lt1.push_back(i);v.push_back(i);}intbegin1=clock();lt1.sort();intend1=clock();intbegin2=clock();sort(v.begin(),v.end());intend2=clock();cout<<"list_time:"<<end1-begin1;cout<<endl;cout<<"vector_time:"<<end2-begin2;return0;}因为sort底层是快排,在debug下不好用(底层是递归很吃亏)在release版本下测试结果如下:
list排序不方便
3.2 vector 与 list 差异
vector与list都是STL中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不同,其主要不同如下:
| 特性 | vector | list |
|---|---|---|
| 底层结构 | 动态顺序表,一段连续空间 | 带头结点的双向循环链表 |
| 随机访问 | 支持随机访问,访问某个元素效率O(1) | 不支持随机访问,访问某个元素效率O(N) |
| 插入和删除 | 任意位置插入和删除效率低,需要搬移元素,时间复杂度为O(N),插入时有可能需要增容,增容:开辟新空间,拷贝元素,释放旧空间,导致效率更低 | 任意位置插入和删除效率高,不需要搬移元素,时间复杂度为O(1) |
| 空间利用率 | 底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高 | 底层节点动态开辟,小节点容易造成内存碎片,空间利用率低,缓存利用率低 |
| 迭代器 | 原生态指针 | 对原生态指针(节点指针)进行封装 |
| 迭代器失效 | 在插入元素时,要给所有的迭代器重新赋值,因为插入元素有可能会导致重新扩容,致使原来迭代器失效,删除时,当前迭代器需要重新赋值否则会失效 | 插入元素不会导致迭代器失效,删除元素时,只会导致当前迭代器失效,其他迭代器不受影响 |
| 使用场景 | 需要高效存储,支持随机访问,不关心插入删除效率 | 大量插入和删除操作,不关心随机访问 |
文章结语
感谢你读到这里~我是「键盘敲碎了雾霭」,愿这篇文字帮你敲开了技术里的小迷雾 💻
如果内容对你有一点点帮助,不妨给个暖心三连吧👇
👍点赞| ❤️收藏| ⭐关注
(听说三连的小伙伴,代码一次编译过,bug绕着走~)
你的支持,就是我继续敲碎技术雾霭的最大动力 🚀
🐶 小彩蛋:
/^ ^\ / 0 0 \ V\ Y /V / - \ / | V__) ||摸一摸毛茸茸的小狗,赶走所有疲惫和bug~我们下篇见 ✨
