hello,家人们,今天咱们来介绍list相关的操作,好啦,废话不多讲,开干.
1:list的介绍
- 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
- 2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
- 3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
- 4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
- 5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list 来说这可能是一个重要的因素)
2:list的使用
2.1:list的构造

cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
void ConstructionAndCopyConstructor()
{
list <int> lt1;
list <int> lt2(5, 10); // 使用5个10初始化容器
for (auto e : lt2)
{
cout << e << " ";
}
cout << endl;
list <int> lt3(lt2); // 拷贝构造函数
for (auto e : lt3)
{
cout << e << " ";
}
cout << endl;
list <int> lt4(lt2.begin(), lt2.end()); // 迭代器区间初始化
for (auto e : lt4)
{
cout << e << " ";
}
cout << endl;
int arr[] = { 1, 2, 3, 4, 5 };
int sz = sizeof(arr) / sizeof(int);
list<int> lt5(arr, arr + sz); //构造数组某段区间的复制品
for (auto e : lt5)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
ConstructionAndCopyConstructor();
return 0;
}

2.2:list的插入与删除

2.2.1:push_front与pop_front
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
void InsertionAndDeletion()
{
list<int> lt;
lt.push_front(1);
lt.push_front(2);
lt.push_front(3);
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
lt.pop_front();
lt.pop_front();
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
InsertionAndDeletion();
return 0;
}

2.2.2:push_back与pop_back
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
void InsertionAndDeletion()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
lt.pop_back();
lt.pop_back();
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
InsertionAndDeletion();
return 0;
}

2.2.3:insert

- 在指定迭代器位置插入一个数。
- 在指定迭代器位置插入n个值为val的数。
- 在指定迭代器位置插入一段迭代器区间(左闭右开)。
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
#include <algorithm>
#include <vector>
void InsertAndErase()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
list<int>::iterator pos = lt.begin();
lt.insert(pos, 25); // 在pos位置插入25
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
lt.insert(pos, 2, 5); // 在pos位置插入2个5
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
vector<int> v(2,6);
lt.insert(pos, v.begin(), v.end()); // 在pos位置插入2个6
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
InsertAndErase();
return 0;
}

2.2.4:erase

- 删除指定迭代器位置的元素。
- 删除指定迭代器区间(左闭右开)的所有元素。
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
#include <algorithm>
#include <vector>
void InsertAndErase()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
list<int>::iterator pos = lt.begin();
lt.insert(pos, 25); // 在pos位置插入25
lt.insert(pos, 2, 5); // 在pos位置插入2个5
vector<int> v(2,6);
lt.insert(pos, v.begin(), v.end()); // 在pos位置插入2个6
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
//在迭代器区间内寻找第一个值为3的元素并返回迭代器
pos = find(lt.begin(), lt.end(), 3);
lt.erase(pos); // 删除pos位置的元素
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
//在迭代器区间内寻找第一个值为5的元素并返回迭代器
pos = find(lt.begin(), lt.end(), 5);
// 删除pos位置到末尾的所有元素
lt.erase(pos, lt.end());
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
InsertAndErase();
return 0;
}

2.3:list的迭代器使用


2.3.1:begin与end
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
#include <algorithm>
#include <vector>
void TestIterator()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
// 正向迭代器
cout << "正向迭代器遍历: ";
list<int>::iterator it = lt.begin();
while(it != lt.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
int main()
{
TestIterator();
return 0;
}

2.3.2:rbegin与rend
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
#include <algorithm>
#include <vector>
void TestIterator()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
// 正向迭代器
cout << "正向迭代器遍历: ";
list<int>::iterator it = lt.begin();
while(it != lt.end())
{
cout << *it << " ";
++it;
}
cout << endl;
//反向迭代器
cout << "反向迭代器遍历: ";
list<int>::reverse_iterator rit = lt.rbegin();
while (rit != lt.rend())
{
cout << *rit << " ";
++rit;
}
}
int main()
{
TestIterator();
return 0;
}

2.4:list的元素获取
2.4.1:front与back

cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
#include <algorithm>
#include <vector>
void TestElementAndAcquisition()
{
list<int> lt;
lt.push_back(10);
lt.push_back(20);
list<int>::iterator pos = lt.begin();
lt.insert(pos, 2, 8);
cout << "第一个元素: " << lt.front() << endl;
cout << "最后一个元素: " << lt.back() << endl;
}
int main()
{
TestElementAndAcquisition();
return 0;
}

2.5:list的大小控制
2.5.1:size与empty与clear


cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
#include <algorithm>
#include <vector>
void TestControlCapacity()
{
list<int> lt;
lt.push_back(1);
vector<int> v(3, 5);
//在尾部插入3个5
lt.insert(lt.end(), v.begin(), v.end());
cout << "当前元素个数: " << lt.size() << endl;
cout << "是否为空: " << (lt.empty() ? "是" : "否") << endl;
lt.clear();
cout << "当前元素个数: " << lt.size() << endl;
cout << "是否为空: " << (lt.empty() ? "是" : "否") << endl;
}
int main()
{
TestControlCapacity();
return 0;
}

2.5.2:resize

- 当所给值大于当前的size时,将size扩大到该值,扩大的数据为第二个所给值,若未给出,则默认为容器所存储类型的默认构造函数所构造出来的值。
- 当所给值小于当前的size时,将size缩小到该值。
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
#include <algorithm>
#include <vector>
void TestControlCapacity()
{
list<int> lt;
lt.push_back(1);
lt.resize(5, 10);
cout << "当前元素个数: " << lt.size() << endl;
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
lt.resize(3);
for (auto e : lt)
{
cout << e << " ";
}
}
int main()
{
TestControlCapacity();
return 0;
}

2.6:list的操作函数
2.6.1:sort
sort函数可以将容器当中的数据默认排为升序,不过效率比库中的sort要差很多.
代码1
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
#include <algorithm>
#include <vector>
void TestSort()
{
srand(time(0));
const int N = 1000000;
list<int> lt1;
list<int> lt2;
vector<int> v;
for (int i = 0; i < N; ++i)
{
auto e = rand() + i;
lt1.push_back(e);
v.push_back(e);
}
int begin1 = clock();
//vector排序
sort(v.begin(), v.end());
int end1 = clock();
int begin2 = clock();
//sort的list排序
lt1.sort();
int end2 = clock();
printf("vector sort:%d\n", end1 - begin1);
printf("list sort:%d\n", end2 - begin2);
}
int main()
{
//TestControlCapacity();
TestSort();
return 0;
}

代码2
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
#include <algorithm>
#include <vector>
void TestSort()
{
srand(time(0));
const int N = 1000000;
list<int> lt1;
list<int> lt2;
for (int i = 0; i < N; ++i)
{
auto e = rand();
lt1.push_back(e);
lt2.push_back(e);
}
int begin1 = clock();
// vector
vector<int> v(lt2.begin(), lt2.end());
//
sort(v.begin(), v.end());
// lt2
lt2.assign(v.begin(), v.end());
int end1 = clock();
int begin2 = clock();
lt1.sort();
int end2 = clock();
printf("list copy vector sort copy list sort:%d\n", end1 - begin1);
printf("list sort:%d\n", end2 - begin2);
}
int main()
{
TestSort();
return 0;
}

2.6.2:splice

splice函数用于两个list容器之间的拼接,其有三种拼接方式:
- 将整个容器拼接到另一个容器的指定迭代器位置。
- 将容器当中的某一个数据拼接到另一个容器的指定迭代器位置。
- 将容器指定迭代器区间的数据拼接到另一个容器的指定迭代器位置。
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
#include <algorithm>
#include <vector>
void TestSplice()
{
list<int> lt1(4, 2);
list<int> lt2(4, 5);
lt1.splice(lt1.begin(), lt2); // 将lt2整体插入到lt1的begin位置
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
list<int> lt3(4, 8);
list<int> lt4(4, 9);
// 将lt4的第一个元素插入到lt3的begin位置
lt3.splice(lt3.begin(), lt4, lt4.begin());
for (auto e : lt3)
{
cout << e << " ";
}
cout << endl;
list<int> lt5(4, 3);
list<int> lt6(4, 4);
lt5.splice(lt5.begin(), lt6, lt6.begin(), lt6.end()); // 将lt6的所有元素插入到lt5的begin位置
for (auto e : lt5)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
TestSplice();
return 0;
}

PS:容器当中被拼接到另一个容器的数据在原容器当中就不存在了。(实际上就是将链表当中的指定结点拼接到了另一个容器当中)
2.6.3:remove与remove_if
- remove函数用于删除容器当中特定值的元素。
- remove_if函数用于删除容器当中满足条件的元素。


cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
#include <algorithm>
#include <vector>
void TestRemove()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(2);
lt.push_back(4);
lt.push_back(2);
lt.push_back(5);
cout << "原始元素: ";
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
lt.remove(2); // 删除所有值为2的元素
cout << "删除值为2后的元素: ";
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
lt.remove_if([](int val) {return val % 2 == 1; }); // 删除所有奇数元素
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
TestRemove();
return 0;
}

2.6.4:unique与merge
- unique函数用于删除容器当中连续的重复元素。
- erge函数用于将一个有序list容器合并到另一个有序list容器当中,使得合并后的list容器任然有序。(类似于归并排序)


cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
#include <algorithm>
#include <vector>
void TestUniqueAndMerge()
{
list<int> lt1;
lt1.push_back(1);
lt1.push_back(2);
lt1.push_back(2);
lt1.push_back(3);
lt1.push_back(3);
lt1.push_back(3);
cout << "原始元素: ";
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
lt1.unique(); // 删除相邻重复元素
cout << "删除相邻重复元素后: ";
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
list<int> lt2;
lt2.push_back(1);
lt2.push_back(3);
lt2.push_back(5);
list<int> lt3;
lt3.push_back(2);
lt3.push_back(4);
lt3.push_back(6);
lt2.merge(lt3); // 将lt3合并到lt2,要求两个容器有序
cout << "合并后的元素: ";
for (auto e : lt2)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
TestUniqueAndMerge();
return 0;
}

2.6.5:reverse与swap
- reverse函数用于将容器当中元素的位置进行逆置。
- swap函数用于交换两个容器的内容。
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
#include <algorithm>
#include <vector>
void TestReverseAndSwap()
{
list<int> lt1;
lt1.push_back(1);
lt1.push_back(2);
lt1.push_back(3);
cout << "原始元素: ";
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
lt1.reverse(); // 反转容器元素
cout << "反转后元素: ";
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
list<int> lt2;
lt2.push_back(4);
lt2.push_back(5);
lt2.push_back(6);
cout << "交换前lt1元素: ";
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
cout << "交换前lt2元素: ";
for (auto e : lt2)
{
cout << e << " ";
}
cout << endl;
lt1.swap(lt2); // 交换两个容器的元素
cout << "交换后lt1元素: ";
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
cout << "交换后lt2元素: ";
for (auto e : lt2)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
TestReverseAndSwap();
return 0;
}

2.6.6:assign
assign函数用于将新内容分配给容器,替换其当前内容,新内容的赋予方式有两种:
- 将n个值为val的数据分配给容器。
- 将所给迭代器区间当中的内容分配给容器。

cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <list>
#include <algorithm>
#include <vector>
void TestAssign()
{
list<int> lt;
lt.assign(5, 10);
cout << "assign后元素: ";
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
vector<int> v = { 1, 2, 3, 4, 5 };
lt.assign(v.begin(), v.end()); // 使用v的元素填充容器
cout << "assign后元素: ";
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
TestAssign();
return 0;
}
