目录
1、list的介绍
- list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
- list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
- list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
- 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
- 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要因素
2、list的使用
2.1、list的构造
构造函数 接口说明 1、list() 构造空的list 2、list (size_type n, const value_type& val = value_type()) 构造的list中包含n个值为val的元素 3、list (const list& x) 拷贝构造函数 4、list (InputIterator first, InputIterator last) 用[first, last)区间中的元素构造list
- 1、list()
list<int> lt1;
- 2、list (size_type n, const value_type& val = value_type())
list<int> lt2(5, 3);//构造5个值为3的元素
- 3、list (const list& x)
list<int> lt3(lt2);//用lt2拷贝构造lt3
- 4、list (InputIterator first, InputIterator last)
//1、用l2的[begin(), end())左闭右开的区间构造lt4 list<int> lt4(lt2.begin(), lt2.end()); //2、以数组为迭代器区间构造lt5 int array[] = { 1,2,3,4 }; list<int> lt5(array, array + sizeof(array) / sizeof(int));
2.2、迭代器的使用
函数声明 接口说明 1、begin 返回第一个元素的迭代器 2、end 返回最后一个元素下一个位置的迭代器 3、rbegin 返回第一个元素的reverse_iterator,即end位置 4、rend 返回最后一个元素下一个位置的reverse_iterator,即begin位置
begin和end
begin是返回第一个元素的迭代器,end是返回最后一个元素下一个位置的迭代器。可以通过迭代器进行元素访问:
void test() { list<int> lt(5, 3); list<int>::iterator it = lt.begin(); while (it != lt.end()) //不能用it < lt.end() { cout << *it << " "; //3 3 3 3 3 it++; } }
- 注意:begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
rbegin和rend
和先前学到的string类似,rbegin的第一个元素为尾部end位置,rend返回的是begin的位置。
void test() { list<int> lt; for (int i = 1; i <= 4; i++) { lt.push_back(i);//1 2 3 4 } list<int>::reverse_iterator rit = lt.rbegin(); //或者用auto自动识别类型:auto rit = lt.rbegin(); while (rit != lt.rend()) { cout << *rit << " "; //4 3 2 1 rit++; } }
- 注意:rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动
范围for
范围for的底层就是迭代器实现的,利用其也可进行元素访问:
void test() { list<int> lt; for (int i = 1; i <= 4; i++) { lt.push_back(i);//1 2 3 4 } for (auto e : lt) { cout << e << " ";//1 2 3 4 } }
2.3、list的元素获取
函数声明 接口声明 1、front 返回list第一个节点中值的引用 2、back 返回list最后一个节点中值的引用
front和back
front返回第一个元素,back返回最后一个元素
void test() { list<int> lt; for (int i = 1; i <= 4; i++) { lt.push_back(i);//1 2 3 4 } cout << lt.front() << endl;//1 cout << lt.back() << endl; //4 }
2.4、list的大小
函数声明 接口说明 1、empty 检测list是否为空,是返回true,不是返回false 2、size 返回list中有效节点的个数
empty
empty判断list是否为空
void test() { list<int> lt; for (int i = 1; i <= 4; i++) { lt.push_back(i);//1 2 3 4 } cout << lt.empty() << endl;//0 }
size
size用来获取list中有些元素个数
void test5() { list<int> lt; for (int i = 1; i <= 4; i++) { lt.push_back(i);//1 2 3 4 } cout << lt.size() << endl;//4 }
2.5、list修改的相关函数
函数声明 接口声明 1、push_front 在list首元素前插入值为val的元素 2、pop_front 删除list中第一个元素 3、push_back 在list尾部插入值为val的元素 4、pop_back 删除list中最后一个元素 5、insert 在list position 位置中插入值为val的元素 6、erase 删除list position位置的元素 7、swap 交换两个list中的元素 8、clear 清空list中的有效数据
push_front和pop_front
push_front即头插,pop_front即头删。
void test() { list<int> lt; for (int i = 1; i <= 4; i++) { lt.push_back(i);//1 2 3 4 } lt.push_front(0);//头插0 cout << lt.front() << endl;//0 lt.pop_front();//头删 cout << lt.front() << endl;//1 }
push_back和pop_back
push_back即尾插,pop_back即尾删。
void test6() { list<int> lt; for (int i = 1; i <= 4; i++) { lt.push_back(i);//1 2 3 4 } lt.push_back(9);//尾插9 cout << lt.back() << endl;//9 lt.pop_back();//尾删 cout << lt.back() << endl;//4 }
insert
list中的insert支持下列三种插入方式:
- 在指定位置插入一个值为val的元素
- 在指定位置插入n个值为val的元素
- 在指定位置插入一段左闭右开的迭代器区间
void test() { list<int> lt; for (int i = 1; i <= 4; i++) { lt.push_back(i);//1 2 3 4 } list<int>::iterator pos = find(lt.begin(), lt.end(), 3); //1、在3的位置插入值7 lt.insert(pos, 7); for (auto e : lt) cout << e << " ";//1 2 7 3 4 cout << endl; //2、在3的位置插入5个-1 pos = find(lt.begin(), lt.end(), 3); lt.insert(pos, 5, -1); for (auto e : lt) cout << e << " ";//1 2 7 -1 -1 -1 -1 -1 3 4 cout << endl; //3、在7的位置插入迭代器区间 pos = find(lt.begin(), lt.end(), 7); list<int> lt2(3, 0); lt.insert(pos, lt2.begin(), lt2.end()); for (auto e : lt) cout << e << " ";//1 2 0 0 0 7 -1 -1 -1 -1 -1 3 4 }
erase
erase支持下列两种删除方式:
- 删除在指定迭代器位置的元素
- 删除指定迭代器区间的元素
void test() { list<int> lt; for (int i = 1; i <= 7; i++) { lt.push_back(i);//1 2 3 4 5 6 7 } list<int>::iterator pos = find(lt.begin(), lt.end(), 2); //1、删除2位置的元素 lt.erase(pos); for (auto e : lt) cout << e << " ";//1 3 4 5 6 7 cout << endl; //2、删除值为4后的所有元素 pos = find(lt.begin(), lt.end(), 4); lt.erase(pos, lt.end()); for (auto e : lt) cout << e << " ";//1 3 }
swap
swap用于交换两个list的内容。
void test() { list<int> lt1(5, -1); list<int> lt2(3, 7); lt2.swap(lt1); for (auto e : lt1) cout << e << " "; //7 7 7 cout << endl; for (auto d : lt2) cout << d << " "; //-1 -1 -1 -1 -1 }
clear
clear用来清空list中的有效数据。
void test() { list<int> lt(5, -1); for (auto e : lt) cout << e << " ";//-1 -1 -1 -1 -1 cout << endl; lt.clear(); for (auto e : lt) cout << e << " ";//空 }
2.6、list的操作函数
函数声明 接口说明 1、sort 对list进行排序 2、unique 删除list中的重复元素
sort
list中的sort函数默认排升序。
void test() { list<int> lt; for (int i = 3; i >= -3; i--) { lt.push_back(i);//3 2 1 0 -1 -2 -3 } lt.sort(); for (auto e : lt) cout << e << " ";//-3 -2 -1 0 1 2 3 }
unique
unique是删除list中的重复元素。
void test() { list<int> lt; lt.push_back(5); lt.push_back(1); lt.push_back(3); lt.push_back(2); lt.push_back(2); lt.push_back(5); lt.push_back(-1); lt.push_back(7); lt.sort(); lt.unique(); for (auto e : lt) cout << e << " ";//-1 1 2 3 5 7 }
- 注意:要想对list进行真正的去重,必须先排序。
3、list与vector对比
vector list 底层结构 动态顺序表,一段连续空间 带头结点的双向循环链表 随即访问 支持随机访问,访问某个元素效率O(1) 不支持随机访问,访问某个元素效率O(N) 插入和删除 任意位置插入和删除效率低,需要搬移元素,时间复杂度为O(N),插入时有可能需要增容,增容:开辟新空间,拷贝元素,释放旧空间,导致效率更低 任意位置插入和删除效率高,不需要搬移元素,时间复杂度为O(1) 空间利用率 底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高 底层节点动态开辟,小节点容易造成内存碎片,空间利用率低,缓存利用率低 迭代器 原生态指针 对原生态指针(节点指针)进行封装 迭代器失效 在插入元素时,要给所有的迭代器重新赋值,因为插入元素有可能会导致重新扩容,致使原来迭代器失效,删除时,当前迭代器需要重新赋值否则会失效 插入元素不会导致迭代器失效,删除元素时,只会导致当前迭代器失效,其他迭代器不受影响 使用场景 需要高效存储,支持随机访问,不关心插入删除效率 大量插入和删除操作,不关心随机访问