C++容器list
定义
std::list - cppreference.cn - C++参考手册
- 双向链表:每个元素(节点)包含数据、一个指向前一个节点的指针和一个指向后一个节点的指针
- 非连续存储:元素在内存中不是连续存放的,而是通过指针链接
- 高效修改 :插入和删除操作(包括中间位置)的时间复杂度为 O(1),前提是已知插入/删除位置的迭代器
- 不支持随机访问 :不能通过下标
[] 直接访问第 n 个元素,必须从头或尾遍历,时间复杂度为 O(n)
- 稳定迭代器 :只要不删除元素,插入操作不会使其他元素的迭代器、指针或引用失效。这是
list 相对于 vector 和 deque 的巨大优势
构造函数
1、默认构造函数
创建空的list,长度为0
cpp
复制代码
int main()
{
system("chcp 65001");
list<std::u8string> list1;
cout << "list1.size()= " << list1.size() << endl;
cout << "list1.max_size()= " << list1.max_size() << endl;
}
2、指定大小构造函数
cpp
复制代码
std::string getStringFromU8string(const std::u8string& u8str) {
return std::string(reinterpret_cast<const char*>(u8str.data()), u8str.size());
}
std::u8string getU8stingFromString(const std::string& str) {
return std::u8string(reinterpret_cast<const char8_t*>(str.data()), str.size());
}
int main()
{
system("chcp 65001");
list<std::u8string> list1(4);
cout << "list1.size()= " << list1.size() << endl;
cout << "list1.max_size()= " << list1.max_size() << endl;
for (auto it : list1)
{
cout << "list1-> " << getStringFromU8string(it) << endl;
}
}
3、指定大小与初始值构造函数
cpp
复制代码
int main()
{
system("chcp 65001");
list<std::u8string> list1(4, u8"&&");
cout << "list1.size()= " << list1.size() << endl;
cout << "list1.max_size()= " << list1.max_size() << endl;
for (auto it : list1)
{
cout << "list1-> " << getStringFromU8string(it) << endl;
}
}
4、拷贝构造函数
cpp
复制代码
int main()
{
system("chcp 65001");
list<std::u8string> list1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };
// 拷贝构造函数
list<std::u8string> list2(list1);
cout << "list2.size()= " << list2.size() << endl;
cout << "list2.max_size()= " << list2.max_size() << endl;
for (auto it : list2)
{
cout << "list2-> " << getStringFromU8string(it) << endl;
}
}
5、移动构造函数
cpp
复制代码
int main()
{
system("chcp 65001");
list<std::u8string> list1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };
// 移动构造函数
list<std::u8string> list2(std::move(list1));
cout << "list2.size()= " << list2.size() << endl;
cout << "list2.max_size()= " << list2.max_size() << endl;
for (auto it : list2)
{
cout << "list2-> " << getStringFromU8string(it) << endl;
}
cout << "list1.size()= " << list1.size() << endl;
cout << "list1.max_size()= " << list1.max_size() << endl;
}
6、范围构造函数
cpp
复制代码
int main()
{
system("chcp 65001");
std::array<std::u8string, 4> arr1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };
// 范围构造函数
list<std::u8string> list1(arr1.rbegin(), arr1.rend());
cout << "list1.size()= " << list1.size() << endl;
cout << "list1.max_size()= " << list1.max_size() << endl;
for (auto it : list1)
{
cout << "list1-> " << getStringFromU8string(it) << endl;
}
}
7、指定初始化列表构造函数
cpp
复制代码
int main()
{
system("chcp 65001");
list<std::u8string> list1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };
list<std::u8string> list2{ u8"张三", u8"李四" };
cout << "list1.size()= " << list1.size() << endl;
cout << "list1.max_size()= " << list1.max_size() << endl;
for (auto it : list1)
{
cout << "list1-> " << getStringFromU8string(it) << endl;
}
}
元素访问
不支持下标访问
| 函数 |
描述 |
front() |
返回第一个元素的引用。 |
back() |
返回最后一个元素的引用。 |
cpp
复制代码
int main()
{
system("chcp 65001");
list<std::u8string> list1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };
cout << "list1.size()= " << list1.size() << endl;
cout << "list1.max_size()= " << list1.max_size() << endl;
cout << "list1.front()= " << getStringFromU8string(list1.front()) << endl;
cout << "list1.back()= " << getStringFromU8string(list1.back()) << endl;
}
容量大小
| 函数 |
描述 |
empty() |
如果 list 为空,返回 true。 |
size() |
返回当前元素数量。 |
max_size() |
返回容器可容纳的最大元素数量。 |
cpp
复制代码
int main()
{
system("chcp 65001");
list<std::u8string> list1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };
cout << "list1.empty()= " << boolalpha << list1.empty() << endl;
cout << "list1.size()= " << list1.size() << endl;
cout << "list1.max_size()= " << list1.max_size() << endl;
cout << "list1.front()= " << getStringFromU8string(list1.front()) << endl;
cout << "list1.back()= " << getStringFromU8string(list1.back()) << endl;
}
迭代器
begin-end与rbegin-rend
cpp
复制代码
int main()
{
system("chcp 65001");
list<std::u8string> list1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };
// for循环
for (auto it : list1)
{
cout << "list1-> " << getStringFromU8string(it) << endl;
}
//begin-end
for (auto it = list1.begin(); it != list1.end(); it++)
{
cout << "begin-end list1-> " << getStringFromU8string(*it) << endl;
}
//cbegin-cend
for (auto it = list1.cbegin(); it != list1.cend(); it++)
{
cout << "cbegin-cend list1-> " << getStringFromU8string(*it) << endl;
}
//rbegin-rend
for (auto it = list1.rbegin(); it != list1.rend(); it++)
{
cout << "rbegin-rend list1-> " << getStringFromU8string(*it) << endl;
}
}
修改操作
| 函数 |
描述 |
push_back(value) |
在末尾插入一个元素 |
push_front(value) |
在开头插入一个元素。 |
pop_back() |
删除最后一个元素。 |
pop_front() |
删除第一个元素。 |
emplace_back(args...) |
在末尾就地构造一个元素(不用复制) |
emplace_front(args...) |
在开头就地构造一个元素(不用复制) |
emplace(pos, args...) |
在位置 pos 就地构造一个元素(不用复制) |
insert(pos, value) |
在位置 pos 插入一个元素。 |
insert(pos, n, value) |
在位置 pos 插入 n 个 value。 |
insert(pos, first, last) |
在位置 pos 插入范围 [first, last) 的元素。 |
erase(pos) |
删除位置 pos 的元素,返回下一个元素的迭代器。 |
erase(first, last) |
删除范围 [first, last) 的元素,返回 last 迭代器。 |
clear() |
删除所有元素。 |
resize(n) |
调整大小到 n。如果变大,新元素用默认值初始化(小于实际元素个数,会删除后面的元素) |
swap(other) |
与另一个 list 交换内容。 |
cpp
复制代码
int main()
{
system("chcp 65001");
list<std::u8string> list1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };
//头部添加数据
list1.push_front(u8"哈尔滨");
list1.emplace_front(u8"长春");
// 尾部添加数据
list1.push_back(u8"沈阳");
list1.emplace_back(u8"葫芦岛");
for (auto it : list1)
{
cout << "list1-> " << getStringFromU8string(it) << endl;
}
// 删除元素
list1.pop_front();
list1.pop_back();
// 删除第一个
list1.erase(list1.begin());
// 删除第三个
list1.erase(std::next(list1.begin(), 2));
// 清空list
list1.erase(list1.begin(), list1.end());
for (auto it : list1)
{
cout << "after delete, list1-> " << getStringFromU8string(it) << endl;
}
// 插入数据
list1.insert(list1.begin(), u8"测试1");
list1.insert(std::next(list1.begin(), 1), u8"测试2");
list1.insert(std::next(list1.begin(), 2), 2, u8"&&");
std::array<std::u8string, 2> arr1 = { u8"张三",u8"李四" };
list1.insert(list1.begin(), arr1.begin(), arr1.end());
for (auto it : list1)
{
cout << "after insert, list1-> " << getStringFromU8string(it) << endl;
}
// 调整大小
list1.resize(2);
cout << "list1.size()= " << list1.size() << endl;
cout << "list1.max_size()= " << list1.max_size() << endl;
for (auto it : list1)
{
cout << "after resize, list1-> " << getStringFromU8string(it) << endl;
}
list1.clear();
}
链表操作
| 函数 |
描述 |
splice(pos, other, it) |
将 other 中 it 指向的元素移动到 l 的 pos 位置。O(1) |
splice(pos, other, first, last) |
将 other 中 [first, last) 范围的元素移动到 l 的 pos 位置。O(1) |
remove(value) |
删除所有值为 value 的元素。 |
remove_if(pred) |
删除所有满足谓词 pred 的元素。 |
unique() |
删除连续的重复元素(只保留一个)。 |
unique(pred) |
使用自定义比较函数删除连续的重复元素。 |
sort() |
对元素进行排序(默认升序)。 |
sort(comp) |
使用自定义比较函数排序。 |
reverse() |
反转 list 中元素的顺序。 |
merge(other) |
将已排序的 other 合并到 l 中,并保持有序。other 变为空。 |
cpp
复制代码
int main()
{
system("chcp 65001");
list<std::u8string> list1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };
list<std::u8string> list2 = { u8"张三",u8"李四" };
// 将list2的第一个元素移动到list1的第一个位置
list1.splice(list1.begin(), list2, list2.begin());
// 将list2的前两个元素移动到list1的第一个位置
// list1.splice(list1.begin(), list2, list2.begin(), list2.end());
for (auto it : list1)
{
cout << "afet splice, list1-> " << getStringFromU8string(it) << endl;
}
// 删除排序
list1.remove(u8"张三");
list1.sort();
for (auto it : list1)
{
cout << "afet sort, list1-> " << getStringFromU8string(it) << endl;
}
// 转置
list1.reverse();
for (auto it : list1)
{
cout << "afet reverse, list1-> " << getStringFromU8string(it) << endl;
}
// 合并另外一个list(要求已经排好序)
list1.sort();
list2.sort();
list1.merge(list2);
cout << "afet merge, list1.size()= " << list1.size() << endl;
cout << "afet merge, list2.size()= " << list2.size() << endl;
}
其他
| 特性 |
std::list |
std::vector |
std::deque |
| 任意位置插入/删除 |
O(1) (已知位置) |
O(n) |
O(n) (中间) / O(1) (首尾) |
| 头部插入/删除 |
O(1) |
O(n) |
O(1) |
| 尾部插入/删除 |
O(1) |
O(1) 均摊 |
O(1) |
| 随机访问 |
不支持 |
O(1) |
O(1) |
| 内存布局 |
非连续 (链表) |
连续 |
分段连续 |
| 迭代器失效 |
仅被删除元素的迭代器失效 |
插入/删除可能导致大量失效 |
插入/删除可能导致大量失效 |
splice 操作 |
O(1) |
不支持 |
不支持 |
| 内存开销 |
高 (每个元素有额外的指针开销) |
低 |
中等 |
| 缓存局部性 |
差 |
好 |
中等 |