目录
🌈前言
本篇文章进行STL中list(双向链表)序列容器的学习!!!
🌸 list
🌷1、list的介绍及使用
🌸1.1、list的介绍
- list是可以在常数范围内在任意位置进行插入和删除的序列容器,并且该容器可以前后双向迭代
- list的底层是双向链表结构,双向链表中每个元素存储在互不关联的独立节点中,在节点中听过指针指向其前一个元素和后一个元素来进行链接
- list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能往前进行迭代,已让其简单高效,而list可以往前和往后进行迭代
- list与其他容器相比(array、vector、deque),list通常在任意位置进行插入、移除元素的执行效率更好,尾插尾删效率慢,需要迭代一遍
- list与其他序列容器相比,list和forward_list最大的缺陷是不支持任意位置的访问
比如:
- 要访问list的第n个元素,必须从已知的位置(头结点或尾节点)迭代到该位置,在这段位置上迭代需要线性时间的开销
- list还需要一些额外的空间,以保持每个节点的相关信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)
🌹1.2、list的使用
list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已达到可扩展的能力。以下为list中一些常见的重要接口
🌹1.2.1、list容器常见的构造函数
(constructor)构造函数 | 接口说明 |
---|---|
list() (重点) | 构造空的list |
list(size_type n, const value_type& val = value_type()) | 构造list中包含n个值尾val的元素 |
list (const listr& l) (重点) | 拷贝构造函数 |
list (InputIterator first, InputIterator last) | 使用区间[first, last)中的元素来构造list |
举个栗子🌰:
void TestList()
{
list<int> l1; // 构造空的list
list<int> l2(5, 100); // 构造5个值为100的list
list<int> l3(l2); // 拷贝构造函数
list<int> l4(l3.begin(), l3.end()); // 使用迭代器来构造list
int Array[] = {
1, 2, 3, 4 };
// 以数组为迭代器区间来构造list[Array, Array + 4)
list<int> l5(Array, Array + sizeof(Array) / sizeof(int));
// 使用迭代器进行遍历输出
list<int>::iterator It = l5.begin();
while (It != l5.end())
{
cout << *It << ' ';
++It;
}
cout << endl;
// 使用C++11基于for范围循环进行遍历输出
for (auto e : l5)
cout << e << ' ';
cout << endl;
}
🌺1.2.2、list iterator(迭代器的使用)
函数声明 | 接口说明 |
---|---|
begin + end | 返回第一个元素的迭代器 + 返回最后一个元素的下一个位置的迭代器 |
rbegin + rend | 返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置的reserve_iterator,及begin位置 |
【注意】
- begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
- rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动
举个栗子🌰:
void print_list(const list<int>& l)
{
// 注意这里调用的是list的 begin()const,返回list的常量迭代器
for (list<int>::const_iterator it = l.begin(); it != l.end(); ++it)
{
cout << *it << " ";
// *it = 10; // 编译不通过 --- 被const修饰不能修改
}
cout << endl;
}
int main()
{
int array[] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> l(array, array + sizeof(array) / sizeof(array[0]));
// 使用正向迭代器正向list中的元素
for (list<int>::iterator it = l.begin(); it != l.end(); ++it)
cout << *it << " ";
cout << endl;
// 使用反向迭代器逆向打印list中的元素
for (list<int>::reverse_iterator it = l.rbegin(); it != l.rend(); ++it)
cout << *it << " ";
cout << endl;
return 0;
}
🌻1.2.3、list capacity
函数声明 | 接口说明 |
---|---|
empty | 检测list是否为空,是返回true,否返回false |
size | 返回list节点的有效个数 |
举个栗子🌰:
void TestListCapacity()
{
list<int> v1;
list<int> v2{
1, 2, 3, 4 };
cout << "v1的有效节点个数为: " << v1.size() << '\t'
<< "v1是否为空: " << v1.empty() << endl;
cout << "v2的有效节点个数为: " << v2.size() << '\t'
<< "v是否为空: " << v2.empty() << endl;
}
int main()
{
TestListCapacity();
return 0;
}
🌼1.2.4、list element access
函数声明 | 接口说明 |
---|---|
front | 返回list第一个节点中值(val)的引用 |
back | 返回list最后一个节点中值(val)的引用 |
举个栗子🌰:
void TestList()
{
list<int> v{
1, 2, 3, 4, 5 };
// 输出list中第一个节点的数据
cout << v.front() << endl;
// 输出list中最后一个节点的数据
cout << v.back() << endl;
// 将list第一个节点数据修改成100
v.front() = 100;
for (auto It = v.begin(); It != v.end(); ++It)
cout << *It << ' ';
cout << endl;
// 将list最后一个节点数据修改成200
v.back() = 200;
for (auto It = v.begin(); It != v.end(); ++It)
cout << *It << ' ';
cout << endl;
}
int main()
{
TestList();
return 0;
}
注意:二个接口返回的是这个数据的引用,引用可以充当左值…
🌿1.2.5、list modifiers
函数声明 | 接口说明 |
---|---|
push_back | 在list尾部插入值为val的元素 |
pop_back | 删除list中最后一个元素 |
push_front | 在list首元素前插入值为val的元素 |
pop_front | 删除list中第一个元素 |
insert | 在list position位置前插入值为val的元素 |
erase | 删除list position位置的元素 |