一.什么是list
在 C++ 中,std::list 是标准库提供的一个容器类,用于将数据进行链式存储。链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的。
1.链表的组成:链表由一系列结点组成。
2.结点的组成:1.存储数据元素的数据域 2.存储下一个结点地址的指针域。
STL中的链表是一个双向循环链表,由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器。
二.list与vector的区别
底层实现:
list 是由双向链表实现的,每个元素包含指向前一个和后一个元素的指针。这种实现使得在列表中的任意位置插入和删除元素都是高效的,但对于随机访问元素的性能较差。
vector 是由动态数组实现的,元素在内存中是连续存储的。这种实现使得随机访问元素的性能非常好,但在中间或开头插入/删除元素时会涉及元素的移动,性能相对较低。
动态调整大小:
list 的大小可以动态增长和缩小,因为它使用链表来存储元素,插入和删除操作的性能与列表的大小无关。
vector 的大小也可以动态增长,但在需要重新分配内存时,可能会导致大量的元素复制和内存重分配操作。
访问效率:
list 不支持随机访问,只能通过迭代器进行顺序访问。对于需要频繁插入和删除操作的场景,list 的性能更好。
vector 支持随机访问,可以通过下标直接访问元素。对于需要频繁的随机访问操作,vector 的性能更好。
内存占用:
list 在存储元素时,除了元素本身的值外,还需要额外的空间存储指向前一个和后一个元素的指针。因此,它通常比 vector 使用更多的内存。
vector 在存储元素时,只需要存储元素的值本身和一些额外的控制信息,因此通常比 list 使用更少的内存。
插入和删除操作:
list 对于在任意位置插入和删除元素来说是高效的,因为它只需要修改相邻元素的指针即可,不需要移动其他元素。list 有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector中是不成立的。
vector 对于在末尾插入和删除元素来说是高效的,因为它只需要在数组的末尾进行操作,不需要移动其他元素。但在中间或开头插入/删除元素时,需要移动其他元素。
综上所述,选择使用 list 还是 vector 取决于具体的应用场景和需求。如果需要频繁的插入和删除操作,并且不需要频繁的随机访问元素,可以选择 list。如果需要频繁的随机访问元素,而插入和删除操作较少,可以选择 vector。另外,如果需要在容器的中间位置进行插入和删除操作,并且对访问效率要求不高,可以考虑使用 list。
三.list构造函数
示例:
#include <iostream>
#include <list> //必须包含该头文件
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 作为函数的参数或者返回值时,不能缺少其中的“&”。
四.赋值
示例:
#include <iostream>
#include <list> //必须包含该头文件
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
五.与list长度有关的操作
示例:
#include <iostream>
#include <list> //必须包含该头文件
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
六.list的插入与删除
示例:
#include <iostream>
#include <list> //必须包含该头文件
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
七.获取list表中的数据
示例:
#include <iostream>
#include <list> //必须包含该头文件
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
八.list的互换、反转、排序
示例:
#include <iostream>
#include <list> //必须包含该头文件
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
综上,list更倾向于当你在中间等位置进行多项插入和删除操作时经常用到的。
至此,完结撒花!!!