list直击查看:https://legacy.cplusplus.com/reference/list/list/?kw=list
std::list
是 C++ 标准库中的一个序列容器,它实现了双向链表(doubly linked list)。
list
与 forward_list
非常相似:主要区别在于 forward_list
对象是单向链表,因此只能向前遍历,而以此换取更小的内存占用和更高的效率。
list
和 forward_list
的主要缺点是缺乏按位置直接访问元素的能力;例如,要访问列表中的第六个元素,必须从已知位置(如开头或末尾)开始遍历到该位置,这需要线性时间。此外,它们还会消耗一些额外的内存来存储与每个元素相关的链接信息(这对于包含大量小型元素的大型lis
t可能是一个重要因素)。
因此,我们又叫它双向循环列表。
当然!以下是对 std::list
四种构造函数的详细示例:
std::list<int>
对象) // 使用默认构造函数创建一个空的 std::list
std::list<int> myList;
// 使用填充构造函数创建一个包含 5 个元素,每个元素初始化为 10 的 std::list
std::list<int> myList(5, 10);
// 使用 std::vector 创建一个范围
std::vector<int> vec = {1, 2, 3, 4, 5};
// 使用范围构造函数创建一个 std::list,包含 vector 中的元素
std::list<int> myList(vec.begin(), vec.end());
// 创建一个初始的 std::list
std::list<int> originalList = {1, 2, 3, 4, 5};
// 使用复制构造函数创建一个新的 std::list
std::list<int> copiedList(originalList);
explicit
关键字在 C++ 中用于控制构造函数的隐式转换行为。它防止了构造函数在不经意间被用于类型转换,从而避免可能导致意外错误或不明确的转换。具体来说,explicit
关键字主要用于防止以下两种情况:
explicit
的,只有当构造函数显式地被调用时,它才会被用作转换。如果构造函数没有 explicit
,则编译器可以在需要时自动执行隐式转换。explicit
,那么它可以在赋值或函数参数传递时被自动调用,可能会导致意外的类型转换或逻辑错误。使用 explicit
关键字可以确保构造函数只在你显式地请求时被调用,从而避免这些潜在问题。explicit list (const allocator_type& alloc = allocator_type());
解释:这个构造函数接受一个分配器 alloc
作为参数。如果没有 explicit
,C++ 编译器可能会在需要 std::list
对象的地方用单一的分配器对象隐式地创建 std::list
。比如,在某些模板类中,编译器可能会自动用分配器创建 std::list
。添加 explicit
关键字防止了这种隐式转换,确保只有当明确调用构造函数时才会使用该构造函数。
explicit list (size_type n, const value_type& val = value_type(),
const allocator_type& alloc = allocator_type());
解释:这个构造函数用于创建一个包含 n
个初始化为 val
的元素的 std::list
。如果没有 explicit
,编译器可能会用单一的 size_type
和 value_type
参数隐式地创建一个 std::list
。添加 explicit
关键字防止了这种隐式类型转换,确保只有当显式调用构造函数时才会创建 std::list
。
迭代器使用和vector
,string
使用基本一样,以下是遍历list
:
#include <iostream>
#include <list>
int main() {
// 创建一个包含一些整数的 std::list
std::list<int> myList = { 10, 20, 30, 40, 50 };
// 1. 使用正向迭代器遍历列表并修改元素
std::cout << "Forward iteration (modifiable): ";
for (auto it = myList.begin(); it != myList.end(); ++it) {
*it *= 2; // 将每个元素乘以 2
std::cout << *it << " ";
}
std::cout << std::endl;
// 2. 使用反向迭代器遍历列表
std::cout << "Reverse iteration (modifiable): ";
for (auto rit = myList.rbegin(); rit != myList.rend(); ++rit) {
std::cout << *rit << " ";
}
std::cout << std::endl;
// 3. 使用常量迭代器遍历列表(只读)
std::cout << "Constant forward iteration (read-only): ";
for (auto cit = myList.cbegin(); cit != myList.cend(); ++cit) {
std::cout << *cit << " ";
}
std::cout << std::endl;
// 4. 使用常量反向迭代器遍历列表(只读)
std::cout << "Constant reverse iteration (read-only): ";
for (auto crit = myList.crbegin(); crit != myList.crend(); ++crit) {
std::cout << *crit << " ";
}
std::cout << std::endl;
return 0;
}
在 C++ 标准库中,std::list
提供了一些用于查询容器容量和大小的公共成员函数。这些函数帮助你了解 std::list
的当前状态和限制。以下是对这些函数的详细解释及示例:
empty
检查 std::list
是否为空。如果列表中没有任何元素,它返回 true
;否则,返回 false
。bool empty() const;
示例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList;
// 检查列表是否为空
if (myList.empty()) {
std::cout << "The list is empty." << std::endl;
} else {
std::cout << "The list is not empty." << std::endl;
}
// 添加元素后再次检查
myList.push_back(10);
if (myList.empty()) {
std::cout << "The list is empty." << std::endl;
} else {
std::cout << "The list is not empty." << std::endl;
}
return 0;
}
size
返回 std::list
中元素的数量。返回值是 size_type
size_type size() const;
示例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {1, 2, 3, 4, 5};
// 获取并输出列表的大小
std::cout << "The size of the list is: " << myList.size() << std::endl;
return 0;
}
max_size
返回容器可以容纳的最大元素数量,这个值是系统和实现决定的。size_type max_size() const;
示例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList;
// 获取并输出列表可以容纳的最大元素数量
std::cout << "The maximum size of the list is: " << myList.max_size() << std::endl;
return 0;
}
front
reference front();//返回一个对列表中第一个元素的引用,可以用来修改该元素。
const_reference front() const;
示例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {10, 20, 30, 40, 50};
// 访问并修改第一个元素
myList.front() = 15;
// 输出第一个元素
std::cout << "The first element is: " << myList.front() << std::endl;
// 使用 const_reference 查看第一个元素(只读)
const std::list<int>& constList = myList;
std::cout << "The first element (const) is: " << constList.front() << std::endl;
return 0;
}
back
reference back();//返回一个对列表中最后一个元素的引用,可以用来修改该元素。
const_reference back() const;
示例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {10, 20, 30, 40, 50};
// 访问并修改最后一个元素
myList.back() = 45;
// 输出最后一个元素
std::cout << "The last element is: " << myList.back() << std::endl;
// 使用 const_reference 查看最后一个元素(只读)
const std::list<int>& constList = myList;
std::cout << "The last element (const) is: " << constList.back() << std::endl;
return 0;
}
push_back
void push_back(const value_type& value);//在列表的末尾插入一个新元素,`value` 是插入的值。
示例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {1, 2, 3};
// 在末尾添加一个元素 4
myList.push_back(4);
std::cout << "List after push_back(4): ";
for (const auto& elem : myList) std::cout << elem << " ";
std::cout << std::endl;
return 0;
}
pop_back
void pop_back();//删除列表中的最后一个元素。此操作将缩小列表的大小。
示例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {1, 2, 3, 4, 5};
// 删除最后一个元素
myList.pop_back();
std::cout << "List after pop_back(): ";
for (const auto& elem : myList) std::cout << elem << " ";
std::cout << std::endl;
return 0;
}
insert
iterator insert(const_iterator position, const value_type& value);
iterator insert(const_iterator position, value_type&& value);
iterator insert(const_iterator position, size_type count, const value_type& value);
template <class InputIterator>
iterator insert(const_iterator position, InputIterator first, InputIterator last);
解释:
insert(const_iterator position, const value_type& value)
:在指定位置插入一个元素,value
是插入的值。insert(const_iterator position, value_type&& value)
:在指定位置插入一个元素,value
是右值引用。insert(const_iterator position, size_type count, const value_type& value)
:在指定位置插入指定数量的相同元素。insert(const_iterator position, InputIterator first, InputIterator last)
:在指定位置插入一个范围的元素。示例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {1, 2, 5};
// 在位置 2 插入元素 3
auto it = myList.begin();
std::advance(it, 2);
myList.insert(it, 3);
// 在位置 1 插入两个元素 10
it = myList.begin();
myList.insert(++it, 2, 10);
// 在末尾插入范围
std::list<int> otherList = {20, 30};
myList.insert(myList.end(), otherList.begin(), otherList.end());
std::cout << "List after multiple inserts: ";
for (const auto& elem : myList) std::cout << elem << " ";
std::cout << std::endl;
return 0;
}
erase
iterator erase(const_iterator position);//删除指定位置的元素。
iterator erase(const_iterator first, const_iterator last);//删除指定范围内的元素。
示例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {1, 2, 3, 4, 5};
// 删除位置 2 的元素
auto it = myList.begin();
std::advance(it, 2);
myList.erase(it);
// 删除从位置 1 到位置 3 的元素
it = myList.begin();
auto itEnd = it;
std::advance(it, 1);
std::advance(itEnd, 3);
myList.erase(it, itEnd);
std::cout << "List after erase(): ";
for (const auto& elem : myList) std::cout << elem << " ";
std::cout << std::endl;
return 0;
}
这里要注意的是迭代器Insert和erase失效问题:
在 C++ 中,当你对一个 list
进行元素的插入或删除操作时,通常迭代器的失效问题需要特别注意。
在 std::list
中:
list
中插入元素不会导致其他迭代器失效。也就是说,插入新元素后,已有的迭代器仍然有效。第一个代码中:
void TestListIterator1()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
std::list<int> mylist(array, array + sizeof(array) / sizeof(array[0]));
auto it = mylist.begin();
while (it != mylist.end())
{
mylist.erase(it);
++it;
}
}
这里的问题是,当 mylist.erase(it)
删除当前迭代器 it
指向的元素时,it
本身就已经失效。接着进行 ++it
操作时会引发未定义行为,因为 it
已经指向了一个无效的位置。
修改后的代码: 你可以通过在删除元素时同时移动迭代器来避免这个问题,如下所示:
void TestListIterator()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> mylist(array, array + sizeof(array) / sizeof(array[0]));
auto it = mylist.begin();
while (it != mylist.end())
{
it = mylist.erase(it); // 通过将it指向erase的返回值来处理
}
}
在这段代码中,mylist.erase(it)
会返回指向被删除元素后一个元素的迭代器,这样就能确保 it
在循环中始终是有效的。
splice
(拼接)
splice
用于将元素从一个std::list
转移到另一个std::list
中。
void splice(iterator pos, list& other);
说明: 将other
列表中的所有元素转移到当前列表pos
位置。
void splice(iterator pos, list& other, iterator it);
说明: 将other
列表中由it
指向的元素转移到当前列表pos
位置。
void splice(iterator pos, list& other, iterator first, iterator last);
说明: 将other
列表中从first
到last
(不包括last
)之间的元素转移到当前列表pos
位置。
示例:
#include <iostream>
#include <list>
void test_splice() {
std::list<int> list1 = {1, 2, 3};
std::list<int> list2 = {4, 5, 6};
list1.splice(list1.end(), list2); // 将list2的所有元素移动到list1的末尾
// list1: {1, 2, 3, 4, 5, 6}
// list2: {}
list1.splice(list1.begin(), list1, ++list1.begin()); // 将第二个元素移动到开头
// list1: {2, 1, 3, 4, 5, 6}
}
remove
(移除)
remove
函数用于从列表中移除所有指定值的元素。void remove(const T& value);
说明: 移除列表中所有等于指定值的元素。示例:
#include <iostream>
#include <list>
void test_remove() {
std::list<int> mylist = {1, 2, 3, 2, 4, 2};
mylist.remove(2); // 移除所有值为2的元素
// mylist: {1, 3, 4}
}
remove_if
(条件移除)
remove_if
函数用于移除满足特定条件的元素。template<class Predicate> void remove_if(Predicate pred);
说明: 移除列表中所有满足条件的元素,该条件由谓词函数pred
定义。示例:
#include <iostream>
#include <list>
void test_remove_if() {
std::list<int> mylist = {1, 2, 3, 4, 5, 6};
mylist.remove_if([](int x) { return x % 2 == 0; }); // 移除所有偶数
// mylist: {1, 3, 5}
}
unique
(去重)
unique
函数用于移除列表中连续的重复元素。void unique();
说明: 移除列表中连续的重复元素。
template<class BinaryPredicate> void unique(BinaryPredicate p);
说明: 根据二元谓词p
移除列表中的重复元素。
示例:
#include <iostream>
#include <list>
void test_unique() {
std::list<int> mylist = {1, 1, 2, 3, 3, 4};
mylist.unique(); // 移除连续的重复元素
// mylist: {1, 2, 3, 4}
}
merge
(合并)
merge
函数用于将两个已排序的列表合并成一个,同时保持排序顺序。void merge(list& other);
说明: 将other
列表合并到当前列表中,前提是两个列表都已排序。
template<class Compare> void merge(list& other, Compare comp);
说明: 使用自定义比较函数comp
将other
列表合并到当前列表中。
示例:
#include <iostream>
#include <list>
void test_merge() {
std::list<int> list1 = {1, 3, 5};
std::list<int> list2 = {2, 4, 6};
list1.merge(list2); // 将list2合并到list1
// list1: {1, 2, 3, 4, 5, 6}
// list2: {}
}
sort
(排序)
sort
函数用于对列表中的元素进行排序。void sort();
说明: 将列表中的元素按升序排序。
template<class Compare> void sort(Compare comp);
说明: 使用自定义比较函数comp
对列表中的元素进行排序。
示例:
#include <iostream>
#include <list>
void test_sort() {
std::list<int> mylist = {4, 1, 3, 2, 5};
mylist.sort(); // 按升序排序
// mylist: {1, 2, 3, 4, 5}
}
reverse
(反转)
reverse
函数用于将列表中的元素顺序反转。void reverse();
说明: 将列表中的元素顺序反转。示例:
#include <iostream>
#include <list>
void test_reverse() {
std::list<int> mylist = {1, 2, 3, 4, 5};
mylist.reverse(); // 反转元素顺序
// mylist: {5, 4, 3, 2, 1}
}
总结
splice
:用于在列表之间移动元素。remove
:移除指定值的元素。remove_if
:移除满足条件的元素。unique
:移除连续的重复元素。merge
:合并两个已排序的列表。sort
:对列表中的元素进行排序。reverse
:反转列表中的元素顺序。这些操作为处理和管理std::list
中的元素提供了强大的工具,非常适合在实际开发中使用。
std::list
是C++标准库中的双向链表容器,具有常数时间内插入和删除元素的优势。std::list
提供了四种构造函数:默认构造、填充构造、范围构造和拷贝构造,其中部分构造函数使用了explicit
关键字来防止意外的类型转换。std::list
的迭代器使用和std::vector
、std::string
基本一致,可以进行正向、反向、只读遍历。std::list
提供了丰富的成员函数,如empty
、size
、max_size
用于查询容器状态,front
、back
用于访问首尾元素,以及push_back
、pop_back
、insert
、erase
等用于元素的增删操作。std::list
的splice
、remove
、remove_if
、unique
、merge
、sort
、reverse
等成员函数提供了强大的容器管理功能,可以灵活地处理和操作列表中的元素。std::list
进行插入和删除操作时,需要注意迭代器可能会失效的问题,应该及时更新迭代器或使用安全的方式操作。扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有