个人主页:平行线也会相交💪
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创
收录于专栏【C++之路】💌
本专栏旨在记录C++的学习路线,望对大家有所帮助🙇
希望我们一起努力、成长,共同进步。🍓
list
是STL中的一种容器,底层其实就是一个双向链表。
既然底层实现是双向链表,所以list
重要的一点就是插入和删除操作的时间复杂度为常数时间O(1),这是因为链表的结构不需要像数组一样进行内存重排。
当然,如果要频繁访问链表中的元素,需要沿着链表进行遍历,这导致list容器
访问操作的时间复杂度为O(n)。
下面将对list中的常见的用法进行一一介绍。
目录
- 一、创建变量
- 二、增删查改
- 1️⃣插入元素
- 2️⃣删除
- 3️⃣查找和修改
- 三、list大小计算
- 四、迭代器遍历
- 五、常见算法
- 1️⃣排序
- 2️⃣删除指定值-remove()
- 3️⃣链表元素转移-splice()
一、创建变量
下面链表变量的创建:
list<int> it1;//创建一个空的list
list<int> it2 = { 1,2,3,4,5 };//创建一个带有初始元素的list
二、增删查改
1️⃣插入元素
插入元素总共分为三种:尾插、头插、任意位置插入。
尾插(push_back()
):
list<int> lt1;
lt1.push_back(1);
lt1.push_back(2);
头插(push_front()
):
list<int> lt1;
lt1.push_front(1);
lt1.push_front(2);
任意位置插入删除(insert()
):
//在第三个位置进行插入10
list<int> lt1;
lt1.push_back(1);
lt1.push_back(2);
lt1.push_back(3);
lt1.push_back(4);
list<int>::iterator it = lt1.begin();
for (size_t i = 0; i < 2; i++)
{
it++;
}
lt1.insert(it, 10);
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
2️⃣删除
//删除的节点中数据为3的节点
list<int> lt1;
lt1.push_back(1);
lt1.push_back(2);
lt1.push_back(3);
lt1.push_back(4);
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
list<int>::iterator it = lt1.begin();
it = find(lt1.begin(), lt1.end(), 3);
//判断是否查找成功
if (it != lt1.end())
{
lt1.erase(it);
//节点此时已经被删除了,当前的迭代器失效
//*it *= 10;
}
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
下面来删除list中的偶数元素:
list<int> lt1;
lt1.push_back(1);
lt1.push_back(2);
lt1.push_back(3);
lt1.push_back(4);
list<int>::iterator it = lt1.begin();
while (it != lt1.end())
{
if (*it % 2 == 0)
{
it = lt1.erase(it);
}
else
{
it++;
}
}
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
3️⃣查找和修改
这里我们需要注意一点:std::list
没有提供内置的find()函数。
原因主要有两点:
第一:遍历代替索引访问:由于std::list是一个双向链表,不支持通过索引来直接访问元素
。相反,要访问或查找元素,需要使用迭代器进行迭代操作。第二:链表的特点是插入和删除元素的时间复杂度为O(1),但访问元素的时间复杂度为O(n),其中n是链表长度。相比之下,std::vector的访问时间复杂度为O(1)。由于
链表不支持快速随机访问,使用线性搜索遍历整个链表可能是更高效的操作
。
举例:
//在链表中查找节点中数据为3的节点,如果查找成功,将该数据的数据*10
list<int> lt1;
lt1.push_back(1);
lt1.push_back(2);
lt1.push_back(3);
lt1.push_back(4);
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
list<int>::iterator it = lt1.begin();
it = find(lt1.begin(), lt1.end(), 3);
//判断是否查找成功
if (it != lt1.end())
{
//查找成功则将迭代器位置的数据*10
*it *= 10;
}
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
}
可以看到查找成功并将该节点的数据*10。
三、list大小计算
std::list
提供了size()函数,用于返回链表中元素的数量。
四、迭代器遍历
list<int> lt1 = { 1,2,3,4,5 };
for (auto it = lt1.begin(); it != lt1.end(); it++)
{
(*it)++;
cout << *it << " ";
}
cout << endl;
五、常见算法
1️⃣排序
list<int> lt = { 12,56,2,95,35,78,47 };
lt.sort();
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
2️⃣删除指定值-remove()
这里需要注意的是:remove()函数会移除链表中所有
与指定值相等的元素,而不仅仅是第一个匹配项。这与erase()函数的行为不同,erase()函数通常只移除第一个
匹配项。
list<int> lt1 = { 12,56,2,95,35,78,47 };
lt1.remove(56);
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
如果链表中没有想要删除的指定值,则remove()函数不会作任何事情,也不会报错。请看举例:
3️⃣链表元素转移-splice()
在STL中,std::list提供了splice()函数,用于将一个链表的元素或者一个元素范围转移到另一个链表中。
splice()函数
共有3个版本:
void splice(const_iterator position, list& x);
void splice(const_iterator position, list& x, const_iterator i);
void splice(const_iterator position, list& x, const_iterator first, const_iterator last);
下面对splice()函数
的3个版本进行举例,请看:
list<int> lt1 = { 1,2,3,4 };
list<int> lt2 = { 10,20,30,40 };
list<int> lt3 = { 1,2,3,4 };
list<int> lt4 = { 10,20,30,40 };
list<int> lt5 = { 1,2,3,4 };
list<int> lt6 = { 10,20,30,40 };
// 将lt2中的所有元素移动到lt1的末尾
lt1.splice(lt1.end(), lt2);
for (auto e : lt1)
cout << e << " ";
cout << endl;
// 将lt4中的第二个元素移动到lt3的开头
auto it3 = lt3.begin();
auto it4 = lt4.begin();
it4++;
lt3.splice(it3, lt4, it4);
for (auto e : lt3)
cout << e << " ";
cout << endl;
//将lt6中的20 30 40移动到lt5的最后位置
auto first = ++lt6.begin();
auto end = lt6.end();
lt5.splice(lt5.end(), lt6, first, end);
for (auto e : lt5)
cout << e << " ";
cout << endl;
运行结果如下:
好了,以上就是本文的全部内容,主要对list的一些基本语法和用法进行了介绍。
就到这里吧,再见啦友友们!!!