深入探索 C++ STL 中的 std::list
容器
在 C++ 标准模板库(STL)中,std::list
是一种非常灵活且功能强大的容器。它基于双向循环链表实现,提供了高效的插入和删除操作,同时支持双向迭代器。本文将通过一系列示例代码,深入探讨 std::list
的构造、操作、排序以及与其他容器的比较,帮助读者更好地理解和使用这一强大的工具。
1. std::list
的构造方式
std::list
提供了多种构造方式,可以根据不同的需求灵活创建链表。以下是几种常见的构造方法:
1.1 默认构造
cpp复制
list<int> l1;
这种方式会创建一个空的链表,不包含任何元素。
1.2 指定范围构造
cpp复制
list<int> l2(l1.begin(), l1.end());
这种方式会根据给定的迭代器范围构造链表,l2
将包含 l1
中的所有元素。
1.3 指定元素构造
cpp复制
list<int> l3(5, 8);
这种方式会创建一个包含 5 个值为 8 的元素的链表。
1.4 拷贝构造
cpp复制
list<int> l4(l3);
这种方式会创建一个与 l3
完全相同的链表。
2. std::list
的基本操作
std::list
提供了一系列操作接口,用于插入、删除、访问元素等。以下是一些常用操作的示例:
2.1 插入操作
cpp复制
list<int> l;
l.push_back(1); // 在链表尾部插入元素
l.push_front(2); // 在链表头部插入元素
此外,还可以使用迭代器指定插入位置:
cpp复制
list<int>::iterator it = l.begin();
l.insert(it, 3); // 在迭代器指向的位置插入元素
2.2 删除操作
cpp复制
l.pop_back(); // 删除链表尾部的元素
l.pop_front(); // 删除链表头部的元素
使用迭代器删除指定元素:
cpp复制
l.erase(it); // 删除迭代器指向的元素
还可以删除指定范围内的元素:
cpp复制
l.erase(l.begin(), --l.end());
2.3 清空链表
cpp复制
l.clear();
2.4 元素访问
std::list
不支持随机访问,因此不能使用 []
或 .at()
方法。但可以通过迭代器访问元素:
cpp复制
list<int>::iterator it = l.begin();
cout << *it << endl; // 访问迭代器指向的元素
3. std::list
的大小操作
std::list
提供了 size()
和 empty()
方法,用于获取链表的大小和判断是否为空:
cpp复制
cout << l.size() << endl; // 获取链表大小
cout << l.empty() << endl; // 判断链表是否为空
此外,还可以通过 resize()
方法调整链表的大小:
cpp复制
l.resize(8); // 将链表大小调整为 8
l.resize(2); // 将链表大小调整为 2
4. std::list
的排序与反转
std::list
提供了 sort()
和 reverse()
方法,用于对链表进行排序和反转:
4.1 反转链表
cpp复制
l.reverse();
4.2 排序
std::list
的 sort()
方法默认按照从小到大的顺序对元素进行排序:
cpp复制
l.sort();
如果需要自定义排序规则,可以传入一个比较函数:
cpp复制
bool my_comp(int a, int b) {
return a > b;
}
l.sort(my_comp); // 按照自定义规则排序
5. std::list
的高级用法
5.1 自定义数据类型排序
std::list
可以存储自定义数据类型,并通过自定义比较函数进行排序。例如,定义一个 person
类,并按照年龄升序、身高降序排序:
cpp复制
class person {
public:
int m_id;
int m_age;
int m_height;
person(int id, int age, int height) : m_id(id), m_age(age), m_height(height) {}
};
bool my_comp(person p1, person p2) {
if (p1.m_age == p2.m_age) {
return p1.m_height > p2.m_height;
} else {
return p1.m_age < p2.m_age;
}
}
list<person> p;
p.push_back(person(1001, 22, 159));
p.push_back(person(1002, 18, 168));
p.push_back(person(1003, 22, 179));
p.push_back(person(1004, 19, 181));
p.sort(my_comp);
5.2 赋值与交换
std::list
提供了多种赋值和交换操作:
cpp复制
list<int> l1;
l1.push_back(1);
l1.push_back(2);
list<int> l2 = l1; // 赋值操作
l1.swap(l2); // 交换两个链表的内容
6. std::list
与其他容器的比较
std::list
是一种基于双向循环链表的容器,与其他容器(如 std::vector
和 std::deque
)相比,具有以下特点:
-
插入和删除效率高:
std::list
在链表头部、尾部或中间插入和删除元素的时间复杂度为 O(1),而std::vector
和std::deque
在中间插入和删除元素时可能需要移动大量元素。 -
不支持随机访问:
std::list
不支持随机访问,因此不能使用[]
或.at()
方法。如果需要随机访问,建议使用std::vector
或std::deque
。 -
内存分配灵活:
std::list
的内存分配是动态的,每个元素单独分配内存,因此内存消耗相对较大。而std::vector
和std::deque
的内存分配是连续的,内存利用率更高。
7. 总结
std::list
是 C++ STL 中一个非常强大的容器,适用于需要频繁插入和删除元素的场景。通过本文的介绍,读者可以更好地理解和使用 std::list
,并根据实际需求选择合适的容器类型。希望本文对您有所帮助!