LIST容器
list概述
std::list
template < class T, class Alloc = allocator<T> > class list;
列表
列表是序列容器,允许在序列中的任何位置执行恒定时间插入和擦除操作,并在两个方向上进行迭代。
列表容器以双向链表的形式实现;双向链表可以将它们包含的每个元素存储在不同且不相关的存储位置。排序是通过与每个元素的关联在内部保持的,该关联链接到它前面的元素,以及与它后面的元素的链接。
它们与 forward_list 非常相似:主要区别在于forward_list对象是单链表,因此它们只能向前迭代
,以换取更小、更高效的性能。
与其他基本标准序列容器(数组、向量和 deque)相比,列表在插入、提取和移动已获得迭代器的容器内的任何位置的元素方面通常表现更好
,因此在大量使用这些元素的算法(如排序算法)中也是如此。
与这些其他序列容器相比,列表s 和 forward_lists 的主要缺点是它们无法通过其位置直接访问元素;例如,要访问列表中的第六个元素,必须从已知位置(如开始或结束)迭代到该位置,这需要它们之间的线性时间。它们还会消耗一些额外的内存,以保持与每个元素关联的链接信息(这可能是小型元素的大型列表的一个重要因素)。
容器属性
序列
序列容器中的元素按严格的线性顺序排序。各个元素通过它们在此序列中的位置进行访问。
双向链表
每个元素都保留有关如何定位下一个和上一个元素的信息,允许在特定元素(甚至整个范围)之前或之后进行恒定时间插入和擦除操作,但不能直接随机访问。
分配器感知
容器使用分配器对象来动态处理其存储需求。
模板参数
T
元素的类型
别名为成员类型 list::value_type。
分配
用于定义存储分配模型的分配器对象的类型。默认情况下,使用分配器类模板,该模板定义了最简单的内存分配模型,并且与值无关。
别名为成员类型 list::allocator_type。
例子
std::list 是 C++ 标准库中的双向链表(doubly linked list)容器,它提供了高效的插入和删除操作,但不支持随机访问元素。下面简要介绍一下 std::list 的底层实现机制和一个简单的示例。
底层实现机制
std::list 使用双向链表作为其底层数据结构,每个节点(node)包含两个指针:一个指向前一个节点,一个指向后一个节点。这种结构使得在任意位置插入和删除操作都很高效,因为只需要调整相邻节点的指针即可,不需要像数组那样移动大量元素。
双向链表的结构如下所示:
nullptr <-> Node1 <-> Node2 <-> … <-> NodeN <-> nullptr
其中 nullptr 表示空指针,用来表示链表的头尾。每个节点中会存储实际的数据,比如 int、char、struct 等。
示例
下面是一个简单的示例展示如何使用 std::list 容器:
#include <iostream>
#include <list>
int main() {
// 创建一个空的 std::list 容器
std::list<int> mylist;
// 向 list 中插入元素
mylist.push_back(1); // {1}
mylist.push_back(2); // {1, 2}
mylist.push_front(3); // {3, 1, 2}
mylist.push_back(4); // {3, 1, 2, 4}
// 使用迭代器遍历输出 list 中的元素
std::cout << "List elements: ";
for (auto it = mylist.begin(); it != mylist.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// 在指定位置插入元素
auto it = ++mylist.begin(); // 获取第二个元素的迭代器
mylist.insert(it, 5); // 在第二个元素后面插入 5,{3, 5, 1, 2, 4}
// 删除元素
mylist.pop_front(); // 删除第一个元素,{5, 1, 2, 4}
mylist.pop_back(); // 删除最后一个元素,{5, 1, 2}
// 输出修改后的 list 元素
std::cout << "Modified List elements: ";
for (auto it = mylist.begin(); it != mylist.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
示例解释
1,首先,我们创建了一个 std::list 类型的空列表 mylist。
2,使用 push_back() 和 push_front() 方法向列表中添加元素。
3,使用迭代器 begin() 和 end() 遍历输出列表中的元素。
4,使用 insert() 在指定位置插入元素。
5,使用 pop_front() 和 pop_back() 方法删除第一个和最后一个元素。
6,最后,再次使用迭代器遍历输出修改后的列表元素。
这个例子展示了 std::list 容器的基本操作,包括插入、删除和遍历元素等,利用了其底层双向链表的特性,使得这些操作都能够高效地执行。
list函数
构造函数
std::list 的构造函数可以分为以下几类:
默认构造函数:
std::list();
创建一个空的双向链表。链表中不包含任何元素。
带有元素个数和元素初值的构造函数:
explicit std::list(size_type count, const T& value = T());
创建一个包含 count 个元素的链表,每个元素的值都是 value。例如:
std::list<int> mylist(5, 10); // 创建一个包含5个值为10的元素的链表
范围构造函数:
template<class InputIterator>
std::list(InputIterator first, InputIterator last);
从迭代器范围 [first, last) 中构造链表,将范围内的元素复制到新建的链表中。例如:
int arr[] = {
1, 2, 3, 4, 5};
std::list<int> mylist(arr, arr + 5); // 从数组中复制元素到链表
拷贝构造函数:
std::list(const std::list& other);
使用另一个 std::list 对象 other 中的元素创建新的链表。例如:
std::list<int> original = {
1, 2, 3};
std::list<int> copy = original; // 使用拷贝构造函数创建副本
移动构造函数:
std::list(std::list&& other) noexcept;
使用另一个 std::list 对象 other 中的元素创建新的链表,并接管 other 的资源。移动构造函数通常比拷贝构造函数更高效。例如:
std::list<int> source = {
1, 2, 3};
std::list<int> dest = std::move(source); // 使用移动构造函数
示例
下面是一个综合示例,展示了 std::list 的不同构造函数的使用方式:
#include <iostream>
#include <list>
int main() {
// 默认构造函数创建空链表
std::list<int> empty_list;
// 使用带有元素个数和初值的构造函数
std::list<int> filled_list(5, 10); // 包含5个值为10的元素的链表
// 使用范围构造函数
int arr[] = {
1, 2, 3, 4, 5};
std::list<int> range_list(arr, arr + 5); // 从数组中复制元素到链表
// 使用拷贝构造函数
std::list<int> original = {
1, 2, 3};
std::list<int> copy = original; // 创建副本
// 使用移动构造函数
std::list<int> source = {
4, 5, 6};
std::list<int> dest = std::move(source); // 移动构造函数
// 输出链表中的元素
std::cout << "Filled list elements:";
for (auto& elem : filled_list) {
std::cout << " " << elem;
}
std::cout << std::endl;
std::cout << "Range list elements:";
for (auto& elem : range_list) {
std::cout << " " << elem;
}
std::cout << std::endl;
std::cout << "Copy list elements:";
for (auto& elem : copy) {
std::cout << " " << elem;
}
std::cout << std::endl;
std::cout << "Moved list elements:";
for (auto& elem : dest) {
std::cout