在 C++ 中,std::list
是标准库提供的一个容器类,用于将数据进行链式存储。链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的。
STL中的链表是一个双向循环链表,由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器。
底层实现:
list
是由双向链表实现的,每个元素包含指向前一个和后一个元素的指针。这种实现使得在列表中的任意位置插入和删除元素都是高效的,但对于随机访问元素的性能较差。vector
是由动态数组实现的,元素在内存中是连续存储的。这种实现使得随机访问元素的性能非常好,但在中间或开头插入/删除元素时会涉及元素的移动,性能相对较低。动态调整大小:
list
的大小可以动态增长和缩小,因为它使用链表来存储元素,插入和删除操作的性能与列表的大小无关。vector
的大小也可以动态增长,但在需要重新分配内存时,可能会导致大量的元素复制和内存重分配操作。访问效率:
list
不支持随机访问,只能通过迭代器进行顺序访问。对于需要频繁插入和删除操作的场景,list
的性能更好。vector
支持随机访问,可以通过下标直接访问元素。对于需要频繁的随机访问操作,vector
的性能更好。内存占用:
list
在存储元素时,除了元素本身的值外,还需要额外的空间存储指向前一个和后一个元素的指针。因此,它通常比 vector
使用更多的内存。vector
在存储元素时,只需要存储元素的值本身和一些额外的控制信息,因此通常比 list
使用更少的内存。插入和删除操作:
list
对于在任意位置插入和删除元素来说是高效的,因为它只需要修改相邻元素的指针即可,不需要移动其他元素。list
有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector
中是不成立的。vector
对于在末尾插入和删除元素来说是高效的,因为它只需要在数组的末尾进行操作,不需要移动其他元素。但在中间或开头插入/删除元素时,需要移动其他元素。综上所述,选择使用 list
还是 vector
取决于具体的应用场景和需求。如果需要频繁的插入和删除操作,并且不需要频繁的随机访问元素,可以选择 list
。如果需要频繁的随机访问元素,而插入和删除操作较少,可以选择 vector
。另外,如果需要在容器的中间位置进行插入和删除操作,并且对访问效率要求不高,可以考虑使用 list
。
构造函数原型 | 解释 | |
---|---|---|
1 | list |
默认构造函数, 采用模板类实现 |
2 | list(lt.begin(), lt.end()) | 将lt[begin, end)区间中的元素拷贝给本身 |
3 | list(n, Element) | 构造函数将n个Element(元素)拷贝给本身 |
4 | list(const list <) | 拷贝构造函数 |
示例:
#include
#include
//必须包含该头文件
using namespace std;
void printVec(list<int> &v)
{
for (list<int>::iterator At = v.begin(); At != v.end(); At++)
{
cout << *At << " ";
}
cout << endl;
}
void printVec(list<double> &v)
{
for (list<double>::iterator At = v.begin(); At != v.end(); At++)
{
cout << *At << " ";
}
cout << endl;
}
void test01()
{
list<int> v1;
v1.push_back(10); //添加元素
v1.push_back(20);
printVec(v1);
list<int> v2(v1.begin(), v1.end());
printVec(v2);
list<double> v3(5, 6.32);
printVec(v3);
list<double> v4(v3);
printVec(v4);
}
int main()
{
test01();
system("pause");
return 0;
}
//result
10 20
10 20
6.32 6.32 6.32 6.32 6.32
6.32 6.32 6.32 6.32 6.32
注意:
list 作为函数的参数或者返回值时,不能缺少其中的“&”。
函数原型: = 、assign | 解释 | |
---|---|---|
1 | list& operator=(const list <) | 重载=操作符 |
2 | assign(begin, end) | 将[begin, end)区间中的数据拷贝赋值给本身 |
3 | assign(n, Element) | 将n个Element拷贝赋值给本身 |
示例:
#include
#include
//必须包含该头文件
using namespace std;
void printVec(list<int> &v)
{
for (list<int>::iterator At = v.begin(); At != v.end(); At++)
{
cout << *At << " ";
}
cout << endl;
}
void test01()
{
list<int> v1;
v1.push_back(10); //添加元素
v1.push_back(20);
printVec(v1);
list<int> v2 = v1;
printVec(v2);
list<int> v3;
v3.assign(v1.begin(), v1.end());
printVec(v3);
list<int> v4;
v4.assign(6, 1);
printVec(v4);
}
int main()
{
test01();
system("pause");
return 0;
}
//result
10 20
10 20
10 20
1 1 1 1 1 1
函数原型:empty、size、resize | 解释 | |
---|---|---|
1 | empty() | 判断容器是否为空 |
2 | size() | 返回容器中元素的个数 |
3 | resize(int num) | 重新指定容器的长度为num。若容器变长,则以默认值填充新位置; 如果容器变短,则末尾超出容器长度的元素被删除 |
4 | resize(int num, Element) | 重新指定容器的长度为num。若容器变长,则以Element值填充新位置; 如果容器变短,则末尾超出容器长度的元素被删除 |
示例:
#include
#include
//必须包含该头文件
using namespace std;
void printVec(list<int> &v)
{
for (list<int>::iterator At = v.begin(); At != v.end(); At++)
{
cout << *At << " ";
}
cout << endl;
}
void test01()
{
list<int> v1;
if (v1.empty()) //判断是否为空
{
cout << "当前v1为空!" << endl;
}
v1.push_back(10); //添加元素
v1.push_back(20);
v1.push_back(30);
if (!v1.empty())
{
cout << "v1中元素个数:" << v1.size() << endl;
printVec(v1);
}
v1.resize(5);
printVec(v1);
v1.resize(10, 1);
printVec(v1);
}
int main()
{
test01();
system("pause");
return 0;
}
//result
当前v1为空!
v1中元素个数:3
10 20 30
10 20 30 0 0
10 20 30 0 0 1 1 1 1 1
函数原型:push_back、pop_back、insert、erase、clear | 解释 | |
---|---|---|
1 | push_back(Element) | 尾部插入元素Element |
2 | pop_back() | 删除最后一个元素 |
3 | push_front(Element) | 在容器开头插入一个元素 |
4 | pop_front() | 从容器开头移除第一个元素 |
5 | insert(iterator p, Element) | 迭代器指向位置p插入元素Element |
6 | insert(iterator p, int n, Element) | 迭代器指向位置p插入n个元素Element |
7 | insert(p,iterator start, iterator end) | 在p位置插入[start,end)区间的数据,无返回值 |
8 | erase(iterator p) | 删除迭代器指向的元素 |
9 | erase(iterator start, iterator end) | 删除迭代器从start到end之间的元素 |
10 | remove(elem) | 删除容器中所有与elem值匹配的元素 |
11 | clear() | 删除容器中所有元素 |
示例:
#include
#include
//必须包含该头文件
using namespace std;
void printVec(list<int> &v)
{
for (list<int>::iterator At = v.begin(); At != v.end(); At++)
{
cout << *At << " ";
}
cout << endl;
}
void test01()
{
list<int> v1;
v1.push_back(1); //尾部添加元素
v1.push_back(2);
v1.push_back(3);
v1.push_back(3);
cout << "尾部添加元素: " << endl;
printVec(v1);
v1.pop_back(); //尾部删除元素
cout << "尾部删除元素: " << endl;
printVec(v1);
v1.push_front(100); //头部添加元素
v1.push_front(200);
v1.push_front(300);
cout << "头部添加元素: " << endl;
printVec(v1);
v1.pop_front(); //头部删除元素
v1.pop_front();
cout << "头部删除元素: " << endl;
printVec(v1);
v1.insert(v1.begin(), 100); //插入元素100
cout << "插入元素100: " << endl;
printVec(v1);
v1.insert(v1.begin(), 5, 100); //插入5个元素100
cout << "插入5个元素100: " << endl;
printVec(v1);
v1.erase(v1.begin()); //删除元素
cout << "删除元素v1.begin(): " << endl;
printVec(v1);
v1.remove(100);
cout << "删除所有100元素: " << endl;
printVec(v1);
v1.clear(); //清空容器
printVec(v1);
}
int main()
{
test01();
system("pause");
return 0;
}
//result
尾部添加元素:
1 2 3 3
尾部删除元素:
1 2 3
头部添加元素:
300 200 100 1 2 3
头部删除元素:
100 1 2 3
插入元素100:
100 100 1 2 3
插入5个元素100:
100 100 100 100 100 100 100 1 2 3
删除元素v1.begin():
100 100 100 100 100 100 1 2 3
删除所有100元素:
1 2 3
函数原型:front()、back | 解释 | |
---|---|---|
1 | front() | 返回容器中第一个数据元素 |
2 | back() | 返回容器中最后一个数据元素 |
示例:
#include
#include
//必须包含该头文件
using namespace std;
void test01()
{
list<int> v1 = { 1, 2, 3, 4, 5, 6 };
cout << "v1.front() = " << v1.front() << endl;
cout << "v1.back() = " << v1.back() << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
//result
v1.front() = 1
v1.back() = 6
函数原型:swap、reverse、sort | 解释 | |
---|---|---|
1 | swap(list lt) | 将lt中元素与本身的元素互换 |
2 | reverse() | 反转链表 |
3 | sort() | 链表排序 |
示例:
#include
#include
//必须包含该头文件
using namespace std;
void printVec(list<int> &v)
{
for (list<int>::iterator At = v.begin(); At != v.end(); At++)
{
cout << *At << " ";
}
cout << endl;
}
void test01()
{
list<int> v1 = { 9, 5, 7, 8, 6 };
list<int> v2 = { 5, 4, 3, 2, 1 };
v1.swap(v2); //互换v1与v2中的元素
cout << "list v1 : " ;
printVec(v1);
cout << "list v2 : " ;
printVec(v2);
v2.sort(); //链表排序
cout << "v2链表排序 : ";
printVec(v2);
v2.reverse(); //反转链表v2
cout << "v2反转链表 : ";
printVec(v2);
}
int main()
{
test01();
system("pause");
return 0;
}
//result
list v1 : 5 4 3 2 1
list v2 : 9 5 7 8 6
v2链表排序 : 5 6 7 8 9
v2反转链表 : 9 8 7 6 5