STL --- 二、容器 (2)List

目录

1、std::list 的特点

2、std::list 常用的 API

3、std::list 使用的例子

4、std::list 一些坑


1、std::list 的特点

(1)list 是 STL 中的一个容器,实现了双向链表结构。
(2)list 中的元素可以在任何位置进行插入和删除操作,不像数组那样需要移动其他元素。
(3)list 中的元素可以动态地增加和减少,不需要预先分配空间。
(4)可以高效地进行插入和删除操作,时间复杂度为 O(1)。
(5)不支持随机访问,只能通过迭代器进行顺序访问。
(6)可以实现元素的排序操作,但是排序效率不如 vector 或 deque。

2、std::list 常用的 API

1. push_front():在 list 的头部插入一个元素
2. push_back():在 list 的尾部插入一个元素。
3. pop_back():从 list 的尾部删除一个元素
4. pop_front():从 list 的头部删除一个元素。
5. clear():清空 vector 中的所有元素。
6. size():返回 list 中元素的数量。。
7. empty():返回 list 是否为空。
8. insert():在指定位置插入一个元素。
9. erase():删除指定位置的元素。
10. splice():将两个 list 合并。
11. sort():按照指定规则对 list 中的元素进行排序。
12. reverse():将 list 中的元素反转。

以上是 std::list 常用的 API,还有其他一些 API 可以根据需要使用。

3、std::list 使用的例子

(1)初始化的几种方式

std::list 是一个双向链表容器,可以通过以下方式进行初始化:

// 1. 默认初始化
std::list<int> mylist;  // 默认初始化一个空的 list

// 2. 列表初始化
std::list<int> mylist = { 1, 2, 3, 4, 5 };  // 使用花括号列表初始化 list

// 3. 拷贝初始化
std::list<int> mylist1 = { 1, 2, 3, 4, 5 };
std::list<int> mylist2(mylist1);  // 拷贝初始化,将 mylist1 拷贝到 mylist2 中

// 4. 范围初始化
std::vector<int> myvector = { 1, 2, 3, 4, 5 };
std::list<int> mylist(myvector.begin(), myvector.end());  // 使用迭代器范围初始化 list

注意事项:

  • 如果使用列表初始化,需要使用花括号 {},而不是圆括号 ()。
  • 如果使用拷贝初始化或范围初始化,需要提供一个同类型的容器作为参数。
  • 初始化 list 时,需要注意元素类型的匹配和拷贝构造函数的实现。

(2)简单一个例子:

该例子演示了如何使用 std::list 存储和操作字符串元素。

#include <iostream>
#include <list>
#include <string>

int main()
{
    std::list<std::string> mylist;

    // 添加元素到列表中
    mylist.push_back("one");
    mylist.push_back("two");
    mylist.push_back("three");
    mylist.push_back("four");

    // 使用迭代器遍历列表中的元素
    std::list<std::string>::iterator it;
    for (it = mylist.begin(); it != mylist.end(); ++it)
    {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    // 在列表中插入元素
    it = mylist.begin();
    ++it;
    mylist.insert(it, "five");

    // 使用迭代器遍历列表中的元素
    for (it = mylist.begin(); it != mylist.end(); ++it)
    {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    // 删除列表中的元素
    it = mylist.begin();
    ++it;
    mylist.erase(it);

    // 使用迭代器遍历列表中的元素
    for (it = mylist.begin(); it != mylist.end(); ++it)
    {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}

4、std::list 一些坑

(1)迭代器失效问题

std::list 的迭代器是不会因为插入或删除元素而失效的,因为它采用的是链表的数据结构,插入和删除操作只需要改变节点的指针,不会影响其他节点的位置。

但是需要注意的是,如果是使用迭代器指向的节点来删除元素,那么在删除后这个迭代器就会失效,因为它指向的节点已经被删除了。此时需要使用 erase() 函数返回的新的迭代器来继续遍历。

(2)排序问题

std::list 的 sort() 函数默认使用的是 operator< 来进行排序,如果需要按照其他方式排序,需要自定义一个比较函数并在 sort() 函数中传入。

需要注意的是,如果比较函数不满足严格弱序关系,那么排序的结果是不确定的。

(3)访问越界问题

std::list 的元素并不是连续存储的,因此不能像 vector 一样使用下标访问元素。如果需要访问某个元素,需要使用迭代器来遍历整个列表。

需要注意的是,访问不存在的元素会导致程序崩溃,因此需要在访问前进行判断。

(4)插入问题

std::list 的 insert() 函数在插入元素时,会在指定位置前插入一个新的元素。如果插入的位置是迭代器 end(),那么新元素会被插入到列表末尾。

需要注意的是,如果插入的元素是一个指针或引用,那么在插入后不能修改这个元素的值,否则会影响列表中其他节点的值。如果需要修改元素的值,需要先将其拷贝到一个新的变量中,再进行修改。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值