做移门图的 网站有哪些,微信小程序开发模板网站,wordpress登录框透明,建设教育局网站硬件价格需要多少钱?引言 在C中#xff0c;std::list 是一个标准库提供的容器类#xff0c;属于C STL#xff08;标准模板库#xff09;。std::list 是一种独特而强大的容器#xff0c;它使用双向链表结构来管理元素。无论是在处理动态数据集合#xff0c;还是在需要频繁进行插入和删除操作时…引言 在C中std::list 是一个标准库提供的容器类属于C STL标准模板库。std::list 是一种独特而强大的容器它使用双向链表结构来管理元素。无论是在处理动态数据集合还是在需要频繁进行插入和删除操作时std::list 都展现了无与伦比的灵活性和效率。与其他线性数据结构如数组和向量相比std::list 让开发者能够在不影响整体性能的情况下轻松地在数据集中间添加或移除元素。
在这篇博客中会以介绍与string类和vector类中相通的函数为主在下一篇博客探索C的工具箱双向链表容器类list2-CSDN博客中会以介绍string类 和vector类中没有的、list新引入的内容为主。
1. list 简介
C 的 std::list 是一个双向链表doubly linked list的实现与 vector 不同list 提供 O(1) 的插入和删除操作但不支持随机访问。使用时需要包含头文件list。 如果将“list”比喻为一个“购物清单”而“list中的元素”就相当于“购物清单上的每一项商品”。
在这个比喻中
- 整个购物清单list是一个容器帮助我们整理和管理购物的内容。
- 每一项商品list中的元素则是清单中具体要购买的内容。
就像我们可以在购物清单上添加、删除或修改商品列表中的元素也可以随时增删改。
std::list具有以下特点 双向链表std::list 中的每个元素都包含指向前一个元素和后一个元素的指针。这使得在链表的任意位置进行插入和删除操作非常快速时间复杂度为O(1)但访问随机元素的效率较低时间复杂度为O(n)。 动态大小std::list 可以根据需要动态增长或收缩能够有效管理动态变化的数据集。 不连续存储与std::vector 不同std::list 中的元素在内存中不必连续存储这为插入和删除操作防止内存重排提供了便利。 支持迭代器std::list 支持常规和反向迭代器可以方便地遍历链表元素。
2.list的构造
基本语法 default (1)
explicit list (const allocator_type alloc allocator_type());
fill (2)
explicit list (size_type n);list (size_type n, const value_type val,const allocator_type alloc allocator_type());
range (3)
template class InputIteratorlist (InputIterator first, InputIterator last,const allocator_type alloc allocator_type());
copy (4)
list (const list x);
list (const list x, const allocator_type alloc);move (5)
list (list x);
list (list x, const allocator_type alloc);initializer list (6)
list (initializer_listvalue_type il,const allocator_type alloc allocator_type());
explicit 关键字用于构造函数目的是为了防止类型转换隐式转换。如果一个构造函数被声明为 explicit那么它只能通过显式的方式来调用而不能用作隐式类型转换。
以下是构造和使用 std::list 的几种常见方法默认使用std
1默认构造函数 创建一个空的 std::list可以使用以下代码
listint myList;
2填充构造函数
explicit list (size_type n);list (size_type n, const value_type val,const allocator_type alloc allocator_type());
上面的构造方法用来创建一个包含n个元素的list并且元素会被初始化为默认值在int类型中默认值是0。
下面的构造方法用来创建一个又n个元素且值会被初始化value的list listint myList(5); // 创建一个包含5个元素的 list listint myList(5, 100); // 创建一个包含5个100的 list 3迭代器范围构造函数
template class InputIteratorlist (InputIterator first, InputIterator last,const allocator_type alloc allocator_type());
#include iostream
#include list
#include vector int main() { vectorint vec {1, 2, 3, 4, 5}; listint myList(vec.begin(), vec.end()); // 使用范围构造函数 return 0;
}
4复制构造函数
list (const list x);
list (const list x, const allocator_type alloc); 第二个构造函数允许自定义分配器。
#include iostream
#include list int main() { listint original {1, 2, 3, 4, 5}; listint copiedList(original); // 使用复制构造函数return 0;
}
5移动构造函数
list (list x);
list (list x, const allocator_type alloc);
同上可以自定义分配器。移动构造函数是在 C11 中引入的它用于高效地构造对象将资源如动态分配的内存从一个对象“转移”到另一个对象而不是进行复制。这种方式能够提高性能尤其是在处理管理资源的对象时例如标准库容器、字符串等。
#include iostream
#include list int main() { std::listint original {1, 2, 3, 4, 5}; std::listint movedList(std::move(original)); // 使用移动构造函数 return 0;
}
6初始化列表构造函数
list (initializer_listvalue_type il,const allocator_type alloc allocator_type());
listint myList {1, 2, 3, 4, 5}; // 使用初始化列表构造函数
7赋值运算符重载构造函数
copy (1)
list operator (const list x);move (2)
list operator (list x);initializer list (3)
list operator (initializer_listvalue_type il);//与初始化列表结合
#include iostream
#include list int main() { // 创建两个 list std::listint list1 {1, 2, 3, 4, 5}; // 初始化 list1 std::listint list2; // 创建空 list2 // 使用赋值运算符将 list1 的内容复制到 list2 list2 list1; // 执行 copy assignment return 0;
}
list容器的迭代器以及空间有关函数等与string类 和vector类的使用相似在此不再赘述不了解的小伙伴可以去看以下博客
C深入学习string类成员函数1默认与迭代_std::string初始化函数-CSDN博客
探索C的存储箱动态数组容器类vector-CSDN博客
3.list的修饰函数
3.1 emplace
emplace 允许在容器中直接构造对象而不是先构造对象再进行拷贝或移动。这样可以避免不必要的性能开销。 - emplace_front(): 在链表头部直接构造元素。 - emplace_back(): 在链表尾部直接构造元素。 - emplace(): 在指定位置直接构造元素。
1. emplace_front() 在链表的开头直接构造元素
std::liststd::string mylist;
mylist.emplace_front(Hello);
mylist.emplace_front(5, A); // 直接构造一个字符串 AAAAA
2. emplace_back() 在链表的末尾直接构造元素
mylist.emplace_back(World);
mylist.emplace_back(4, B); // 直接构造字符串 BBBB
3.emplace() 在链表的指定位置直接构造元素
auto it mylist.begin();
mylist.emplace(it, Inserted); // 在开头插入字符串 Inserted
emplace 与 push 系列的区别 - push_front() / push_back(): 需要先创建一个对象然后再将其拷贝或移动到容器中。 - emplace_front() / emplace_back(): 直接在容器中的位置构造对象省去了拷贝或移动的过程适合构造复杂对象时提高效率。
使用场景 当你需要直接在容器中构造元素并且想避免额外的临时对象构造和销毁时emplace 系列函数非常有用尤其是在需要构造复杂对象或容器时性能优势明显。
3.2 assign
std::list 的 assign() 函数用于替换链表中的元素。它提供了三种重载方式来支持不同的输入类型。以下是每种 assign() 函数的具体说明
range (1)
template class InputIteratorvoid assign (InputIterator first, InputIterator last);fill (2)
void assign (size_type n, const value_type val);initializer list (3)
void assign (initializer_listvalue_type il);
1.范围构造函数 - 功能将链表中的元素替换为 [first, last) 范围内的元素。此函数使用两个迭代器来指定范围可以从另一个容器或范围中拷贝元素。 std::listint mylist;std::vectorint vec {1, 2, 3, 4, 5};mylist.assign(vec.begin(), vec.end()); // 复制 vector 中的所有元素到 list
2.填充构造函数 - 功能将链表中的元素替换为 n 个值为 val 的元素。此函数将链表填充为 n 个相同的元素。 std::listint mylist;mylist.assign(5, 100); // 用 5 个值为 100 的元素填充 list
3.初始化列表构造函数 - 功能将链表中的元素替换为初始化列表 il 中的元素。此函数允许使用 C11 引入的初始化列表语法进行赋值。 std::listint mylist;mylist.assign({1, 2, 3, 4, 5}); // 通过初始化列表填充 list
4.assign() 函数的使用场景
- 范围赋值Range Assign适用于从另一个容器或范围内复制数据例如从 vector 或 array 中将某个范围的元素赋值到 list 中。 - 填充赋值Fill Assign适合需要将链表中的所有元素设置为相同的值时使用例如初始化某个固定大小的列表。 - 初始化列表赋值Initializer List Assign简化了使用固定值集合初始化 list 的过程尤其是在初始化时可以快速赋值。
3.3 push与pop
在 C std::list 中push 和 pop分别用于向链表中添加元素和移除元素。它们有两种常用的形式操作链表头部和尾部的元素。
1push 系列
1. push_front() - 功能在链表头部插入一个元素。 std::listint mylist;mylist.push_front(10); // 在链表头部插入 10mylist.push_front(20); // 在链表头部插入 20链表现在是 {20, 10}
2. push_back() - 功能在链表尾部插入一个元素。 std::listint mylist;mylist.push_back(10); // 在链表尾部插入 10mylist.push_back(20); // 在链表尾部插入 20链表现在是 {10, 20}
2pop 系列
1. pop_front() - 功能移除链表头部的元素。 - 注意此操作不返回被移除的元素。如果链表为空调用此函数会导致未定义行为。 std::listint mylist {10, 20, 30};mylist.pop_front(); // 移除头部的 10链表现在是 {20, 30}
2. pop_back() - 功能移除链表尾部的元素。 - 注意与 pop_front() 一样此操作不返回被移除的元素链表为空时调用会导致未定义行为。 std::listint mylist {10, 20, 30};mylist.pop_back(); // 移除尾部的 30链表现在是 {10, 20}
3.4 其它函数
- insert()在链表的指定位置插入元素或范围内的多个元素。 - swap()交换两个链表的内容。 - erase()删除链表中的某个元素或一段范围内的元素。 - resize()调整链表大小可能会插入或删除元素。 - clear()清空链表删除所有元素。
1. insert()
- 功能在指定位置插入一个或多个元素。 - 重载形式
single element (1)
iterator insert (const_iterator position, const value_type val);
fill (2)
iterator insert (const_iterator position, size_type n, const value_type val);
range (3)
template class InputIterator
iterator insert (const_iterator position, InputIterator first, InputIterator last);1. 插入单个元素 在 position 迭代器处插入 val返回指向新插入元素的迭代器。 2. 插入多个相同值的元素 在 position 处插入 n 个 val。
3. 插入范围内的元素 将 [first, last) 范围内的元素插入到 position 处。
2. swap()
- 功能交换两个 list 容器的内容。 std::listint list1 {1, 2, 3};std::listint list2 {4, 5, 6};list1.swap(list2); // list1 变为 {4, 5, 6}list2 变为 {1, 2, 3}
3. erase()
- 功能删除指定位置的元素或指定范围内的元素。 - 重载形式
iterator erase (const_iterator position);
iterator erase (const_iterator first, const_iterator last);
1. 删除单个元素 删除 position 处的元素返回指向被删除元素后面的元素迭代器。
2. 删除范围内的元素 删除 [first, last) 范围内的所有元素返回指向删除范围后第一个元素的迭代器。
4. resize()
- 功能调整链表的大小。如果新大小比当前小删除多余的元素如果新大小比当前大则插入默认值的元素或指定值的元素。 - 用法
void resize (size_type n);
void resize (size_type n, const value_type val);
1. 仅调整大小 调整链表大小为 n如果新大小比当前大则插入默认值的元素。 2. 调整大小并指定新元素的值 调整链表大小为 n并用 val 填充新插入的元素。 std::listint mylist {1, 2, 3};mylist.resize(5, 100); // 调整大小为 5列表变为 {1, 2, 3, 100, 100}mylist.resize(2); // 缩小大小为 2列表变为 {1, 2}
5. clear()
- 功能清空链表删除所有元素链表大小变为 0但不改变链表的容量。 std::listint mylist {1, 2, 3, 4};mylist.clear(); // 清空列表列表现在为空 通过本篇文章我们详细了解了 C list 容器的基本操作与应用场景。list 提供了双向链表的灵活性能够高效地进行插入、删除等操作尤其在需要频繁修改容器中的元素时表现优异。然而正如我们所讨论的它在随机访问性能上不如其他顺序容器如 vector因此在选择容器时应根据实际需求权衡各个方面。
本篇博客就到此为止了与vector、string容器不同、list新引入的内容都在探索C的工具箱双向链表容器类list2-CSDN博客中有兴趣的小伙伴可以跳转学习