C++STL(2) list容器汇总

C++STL(2) list容器汇总

一、概述

std::list是C++标准库提供的双向链表容器。与std::vector不同,std::list不是基于连续内存存储元素的,而是通过指针链接各个元素。这使得std::list在插入和删除元素时具有更好的性能,但在随机访问元素时性能较差。

下面是std::list的一些特点:

  1. 双向链表std::list的元素以双向链表的形式存储,每个元素都包含指向前一个元素和后一个元素的指针。

  2. 插入和删除:由于链表的特性,std::list在插入和删除元素时效率很高,不需要移动其他元素。插入和删除操作的时间复杂度为O(1)。

  3. 无需重新分配内存:与std::vector不同,std::list不需要在插入和删除元素时重新分配内存,因为它使用指针链接元素。

  4. 没有随机访问:由于std::list不是基于连续内存,因此不能像std::vector那样通过索引进行随机访问。要访问std::list中的元素,需要从头或尾开始遍历链表。

  5. 迭代器稳定性std::list的迭代器在插入和删除操作后保持有效,不会失效或指向无效的元素。

  6. 使用注意:由于std::list的元素不是在连续内存中存储的,因此它的存取速度相对较慢。在大多数情况下,如果需要频繁地进行随机访问或在尾部进行插入/删除操作,std::vector可能更合适。

二、详细介绍及用法

当使用C++的std::list容器时,可以通过多种方式进行初始化。下面是一些常见的初始化std::list容器的方法:

  1. 默认初始化:创建一个空的std::list容器。
std::list<int> myList; // 默认构造函数创建一个空的list
  1. 使用元素范围初始化:使用其他容器中的元素范围初始化std::list容器。
std::vector<int> vec = {1, 2, 3, 4};
std::list<int> myList(vec.begin(), vec.end()); // 使用vec中的元素范围初始化list
  1. 使用重复元素初始化:使用相同的元素值初始化std::list容器。
std::list<int> myList(5, 42); // 初始化包含5个值为42的元素的list
  1. 使用初始化列表初始化:使用大括号初始化列表初始化std::list容器。
std::list<int> myList = {1, 2, 3, 4}; // 使用初始化列表初始化list

当使用C++的std::list容器时,以下是一些常用函数的详细介绍:

  • push_back():在容器的末尾插入一个元素。
std::list<int> myList;
myList.push_back(42); // 在容器末尾插入元素42
  • push_front():在容器的开头插入一个元素。
std::list<int> myList;
myList.push_front(42); // 在容器开头插入元素42
  • pop_back():删除容器末尾的元素。
std::list<int> myList = {1, 2, 3, 4};
myList.pop_back(); // 删除容器末尾的元素,此时容器为 {1, 2, 3}
  • pop_front():删除容器开头的元素。
std::list<int> myList = {1, 2, 3, 4};
myList.pop_front(); // 删除容器开头的元素,此时容器为 {2, 3, 4}
  • size():返回容器中的元素数量。
std::list<int> myList = {1, 2, 3, 4};
std::cout << myList.size() << std::endl; // 输出:4
  • empty():检查容器是否为空。
std::list<int> myList;
if (myList.empty()) {
  std::cout << "容器为空" << std::endl;
} else {
  std::cout << "容器不为空" << std::endl;
}
  • clear():清空容器,删除所有的元素。
std::list<int> myList = {1, 2, 3, 4};
myList.clear(); // 清空容器,此时容器为空
  • begin()end():用于迭代器的起始和结束位置。
std::list<int> myList = {1, 2, 3, 4};

// 使用迭代器遍历容器
for (auto it = myList.begin(); it != myList.end(); ++it) {
  std::cout << *it << " ";
}
std::cout << std::endl; // 输出:1 2 3 4
  • rbegin()rend():用于反向迭代器的起始和结束位置。
std::list<int> myList = {1, 2, 3, 4};

// 使用反向迭代器遍历容器
for (auto it = myList.rbegin(); it != myList.rend(); ++it) {
  std::cout << *it << " ";
}
std::cout << std::endl; // 输出:4 3 2 1
  • insert():在指定位置插入一个或多个元素。
std::list<int> myList = {1, 2, 3, 4};
auto it = myList.begin();
++it; // 将迭代器移动到第二个位置

myList.insert(it, 42); // 在第二个位置插入元素42,此时容器为 {1, 42, 2, 3, 4}

// 在第二个位置插入元素范围
std::vector<int> vec = {5, 6};
myList.insert(it, vec.begin(), vec.end()); // 此时容器为 {1, 5, 6, 42, 2, 3, 4}
  • erase():从容器中删除指定位置或指定范围的元素。
std::list<int> myList = {1, 2, 3, 4, 5};
auto it = myList.begin();
++it; // 将迭代器移动到第二个位置

myList.erase(it); // 删除第二个位置的元素,此时容器为 {1, 3,4, 5}

// 删除指定范围的元素
auto first = myList.begin();
auto last = myList.end();
--last; // 将迭代器移动到最后一个位置
myList.erase(first, last); // 删除第一个位置到最后一个位置之前的元素,此时容器只剩下一个元素:{5}
  • front()back():分别返回容器的第一个元素和最后一个元素的引用。
std::list<int> myList = {1, 2, 3, 4};

int firstElement = myList.front(); // 获取第一个元素,值为1
int lastElement = myList.back(); // 获取最后一个元素,值为4
  • assign():用新的元素替换容器的内容。
std::list<int> myList = {1, 2, 3, 4};

// 用新的元素 {5, 6, 7} 替换容器的内容
myList.assign({5, 6, 7}); // 容器变为 {5, 6, 7}
  • resize():改变容器的大小。
std::list<int> myList = {1, 2, 3, 4};

myList.resize(6); // 将容器的大小调整为6,默认使用0填充剩余的位置,容器变为 {1, 2, 3, 4, 0, 0}

myList.resize(3); // 将容器的大小调整为3,多余的元素被删除,容器变为 {1, 2, 3}
  • remove():删除容器中所有与给定值相等的元素。
std::list<int> myList = {1, 2, 2, 3, 4, 2};

myList.remove(2); // 删除容器中所有值为2的元素,容器变为 {1, 3, 4}
  • reverse():反转容器中的元素顺序。
std::list<int> myList = {1, 2, 3, 4};

myList.reverse(); // 反转容器中的元素顺序,容器变为 {4, 3, 2, 1}
  • sort():对容器中的元素进行排序。
std::list<int> myList = {4, 2, 1, 3};

myList.sort(); // 对容器中的元素进行升序排序,容器变为 {1, 2, 3, 4}
  • merge():将两个已排序的容器合并成一个已排序的容器。
std::list<int> list1 = {1, 3, 5};
std::list<int> list2 = {2, 4, 6};

list1.merge(list2); // 将list2合并到list1中,list1和list2都必须是已排序的容器,合并后list1变为 {1, 2, 3, 4, 5, 6},list2变为空
  • splice():将一个容器的元素移动到另一个容器中的指定位置。
std::list<int> list1 = {1, 2, 3};
std::list<int> list2 = {4, 5};
auto it = list1.begin();
++it; // 将迭代器移动到第二个位置

list1.splice(it, list2); // 将list2中的所有元素移动到list1的第二个位置之前,list1变为 {1, 4, 5, 2, 3},list2变为空
  • unique():用于去除容器中相邻重复的元素,只保留一个副本。该函数会对容器进行就地修改,将重复的元素移除。
std::list<int> myList = {1, 1, 2, 2, 3, 3, 4, 4};

myList.unique(); // 去除相邻重复元素,容器变为 {1, 2, 3, 4}
注意,`unique()`函数只能去除相邻重复的元素。如果要去除所有重复的元素,可以先对容器进行排序,然后再使用`unique()`函数。
  • max_size():返回std::list容器能够容纳的最大元素数量。该函数返回一个无符号整数,表示容器的最大容量。
std::list<int> myList;
std::cout << "最大容量:" << myList.max_size() << std::endl;
注意,`max_size()`返回的是理论上的最大容量,实际分配的容量可能会受到系统限制或可用内存的限制。
  • emplace_back():用于在容器的末尾直接构造一个新元素。与push_back()函数相比,emplace_back()可以直接在容器中构造对象,而不需要创建临时对象。
struct MyStruct {
  int value1;
  std::string value2;
  
  MyStruct(int v1, std::string v2) : value1(v1), value2(v2) {}
};

std::list<MyStruct> myList;

myList.emplace_back(42, "Hello"); // 在容器末尾直接构造一个新元素

// 等效于
myList.push_back(MyStruct(42, "Hello"));

使用`emplace_back()`可以避免创建临时对象,提高效率。

三、结语

std::list作为C++标准库提供的一种双向链表容器,与其他容器(如std::vectorstd::deque)相比,std::list具有一些独特的特性:

  1. 插入和删除操作效率高: 由于std::list是基于链表实现的,插入和删除操作对于任意位置的元素都非常高效,不受容器大小的影响。这使得std::list在需要频繁进行插入和删除操作的场景下具有优势。

  2. 不需要连续内存: std::list使用链表结构存储元素,不要求元素在内存中连续存储。这使得std::list能够处理大量元素或者元素大小变化频繁的情况。

  3. 稳定的迭代器: 在对std::list进行插入和删除操作时,与被操作的元素无关的迭代器仍然保持有效,这是由于链表的特性所决定的。这使得std::list在需要在迭代过程中进行插入和删除操作的场景下非常有用。

然而,std::list也有一些限制和缺点:

  1. 随机访问效率低: 由于链表的特性,std::list不支持通过索引进行随机访问。如果需要经常通过索引来访问元素,使用std::vector可能更合适。

  2. 额外的空间开销: 与其他容器相比,std::list在存储每个元素时需要额外的指针来维护链表结构,这会引入一定的空间开销。

综上所述,std::list在某些特定的应用场景下非常有用,特别是对于频繁进行插入和删除操作、不需要随机访问、或者需要稳定迭代器的情况。然而,在其他情况下,其他容器可能更适合,具体选择取决于具体的需求和性能要求。在选择容器时,需要综合考虑数据结构的特性、操作的复杂度、内存占用和性能要求等因素。

最佳的容器选择取决于特定的用例和需求,没有一种容器适用于所有情况。因此,熟悉各种容器的特性和适用场景非常重要,以便根据具体需求做出正确的选择。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Pigwantofly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值