一直在看数据结构的视频,也在力扣上面刷了一些相关的题目,但是对于c++ 自带的list却从没有正儿八经使用过,所以,今天用一两个小时的时间,把list的用法总结一下,算是扫清一个知识疑惑。

一、注意事项

  1. list是双向链表,可以在常规时间内在list的任意位置插入或删除元素,反之,不能像数组一样直接使用下标[n]来获取元素;
  2. 使用的时候,添加头文件 #include

二、list函数介绍

从官网可以查询到list的介绍,主要分为以下几类:

  1. iterator 迭代器
    可以看到,里面给出了好几种begin、end,它们都有什么区别呢?
    begin,end 传统的迭代器
    rbegin,rend ,reverse,逆迭代器
    cbegin ,cend ,const ,也就是不能通过迭代器更改指向的值
    crbegin,crend,const reverse iterator
  2. capacity 容量

    empty:返回bool值 ,判断list是否为空
    size: 返回list的容量(大小)
    max_size: 可以开辟的最大的容量
  3. element access 元素访问

    front:list的头部值
    back:list的尾部值
  4. modifies 修改
    assign:分配空间
    emplace_front: 头部插入值
    emplace_back: 尾部插入值
    emplace:插入值
    push_front:头部插入值
    push_back:尾部插入值
    insert:插入值
    所以,push与emplace有什么区别呢?
    答: emplace在插入值的时候,不会产生中间变量,具体的大家可以去搜索查证

clear:全部删除
erase:单独擦除
二者区别:erase可以单独删除某些元素,clear直接删除了所有的元素;
swap:交换两个链表,实际是交换两个链表的地址
resize: 重构大小,重构变小的话,后面的元素被删除
5. operation 操作

splice:拼接两个链表
remove:删除,只是把元素移动到头部,然后把begin往后移动,如果要真的删除,需要使用erase和clear
remove_if:满足条件就remove
unique:删除重复的元素,只保留一个
sort:排序
reverse:反转
merge:合并

附上一些代码验证:


#include <list>
#include <iostream>
using namespace std;

template <class T>
void print_list(list<T> my_list)
{
   
    for (typename list<T>::iterator it = my_list.begin(); it != my_list.end(); ++it)
        cout << ' ' << *it;

    cout << '\n';
}

// a predicate implemented as a function:
bool equal_digit(const int &value) {
    return (value == 1); }

// a predicate implemented as a class:
struct is_odd
{
   
    bool operator()(const int &value) {
    return (value % 2) == 1; }
};

int main()
{
   
    //list初始化
    list<int> myListA;         //定义空的链表
    list<int> myListB(4, 100); //定义链表myListB,4个元素,初始值为100
    list<int> myListC(myListB.begin(), myListB.end());
    list<int> myListD(myListC); //使用myListC来初始化myListD

    /*list的函数*/
    //1.assign,assignment 分配
    cout << "----1.assign----" << endl;
    myListA.assign(3, 19);
    print_list(myListA);
    myListA.assign(2, 10);
    print_list(myListA);
    cout << "----------------" << endl;
    //2. iterator 迭代器
    // begin end ;rbegin rend;cbegin cend;crbegin crend
    cout << "----2.iterator----" << endl;
    for (list<int>::iterator it = myListB.begin(); it != myListB.end(); ++it)
        cout << ' ' << *it;
    cout << '\n';
    // for (list<int>::iterator it = myListB.rbegin(); it != myListB.rend(); ++it)
    // cout << ' ' << *it;
    // cout << '\n';
    //const iterator 的使用,可以自增,但是其指向的元素值不可被改变,这里就是cbegin cend的存在意义
    for (auto it = myListB.cbegin(); it != myListB.end(); ++it)
        cout << ' ' << *it;
    //*it=0;
    cout << '\n';
    //reverse iterator 反向迭代器
    int intA[] = {
   111, 26, 3, 45, 5, 6};
    myListA.assign(intA, intA + 6);
    for (auto it = myListA.cbegin(); it != myListA.end(); ++it)
        cout << ' ' << *it;
    cout << '\n';
    cout << "reverse!" << endl;
    for (auto it = myListA.crbegin(); it != myListA.crend(); ++it)
        cout << ' ' << *it;
    cout << '\n';

    //3. capacity
    //empty()
    if (myListA.empty())
        cout << "empty!" << endl;
    else
        cout << "no empty" << endl;
    //size()
    cout << "size:" << myListA.size() << endl;
    //max_size();
    cout << "max_size:" << myListA.max_size() << endl;

    //4. element access 元素访问
    cout << "element front:" << myListA.front();
    cout << "element back:" << myListA.back();
    std::cout << '\n';

    //5.modifies 修改
    //assign 初始化分配 上面提到了
    //emplace_front/ emplace_back/emplace 避免临时变量的产生
    //push_front push_back 会产生临时变量
    // emplace insert
    myListA.emplace_front(1000);
    for (auto &x : myListA)
        std::cout << ' ' << x;
    std::cout << '\n';
    myListA.emplace_back(1000);
    for (auto &x : myListA)
        std::cout << ' ' << x;
    std::cout << '\n';
    myListA.push_front(9);
    myListA.push_back(9);
    for (auto &x : myListA)
        std::cout << ' ' << x;
    std::cout << '\n';
    myListA.insert(myListA.begin(), 30);
    myListA.emplace(myListA.begin(), 300);
    for (auto &x : myListA)
        std::cout << ' ' << x;
    std::cout << '\n';
    //erase clear; erase可以单独删除某些元素,clear直接删除了所有的元素;
    myListA.clear(); //删除所有的元素
    for (auto &x : myListA)
        std::cout << ' ' << x;
    std::cout << '\n';
    cout << "size:" << myListA.size() << endl;
    myListA.assign(4, 88);
    list<int>::iterator itforList;
    itforList = myListA.begin();
    cout << *itforList << endl;
    cout << "size:" << myListA.size() << endl;
    for (auto it = myListA.begin(); it != myListA.end();)
        //myListA.erase(it++);
        it = myListA.erase(it); //返回指向下一个元素的迭代器
    std::cout << '\n';
    //使用erase删除某一个元素
    myListA.assign(intA, intA + 6);
    print_list(myListA);
    for (auto it = myListA.begin(); it != myListA.end();)
    {
   
        if (*it == 4)
            myListA.erase(it++); //返回指向下一个元素的迭代器
        else
        {
   
            it++;
        }
    }
    print_list(myListA);
    //swap
    myListB.assign(intA, intA + 3);
    myListA.swap(myListB); //交换两个链表的内容
    print_list(myListA);
    print_list(myListB);
    /*
    swap函数会交换2个数据类型相同的容器内容。
    本身交换的速度非常快,因为swap在交换的时候并不是完全将2个容器的元素互换,
    而是交换了2个容器内的内存地址。除了数组,其他容器在交换后本质上是将内存地址进行了交换,
    而元素本身在内存中的位置是没有变化的。
    换而言之,如果说有2个房间,名字是a和b,
    那么swap函数交换的是2个房间的名字,
    而房间里的物品根本没有任何移动。
    */
    //resize: 重新设置容器的大小
    myListB.resize(1);
    print_list(myListB);
    myListB.resize(6);
    print_list(myListB);

    //6. operation
    // splice 拼接
    cout << "myListA" << endl;
    print_list(myListA);
    cout << "myListB" << endl;
    print_list(myListB);
    myListA.splice(myListA.begin(), myListB);
    cout << "myListA" << endl;
    print_list(myListA);
    cout << "myListB" << endl;
    print_list(myListB);
    cout << "size:" << myListB.size() << endl;
    //remove remove_if 只是把要删除的元素移动到前端,如果想要真正的删除,需要使用erase clear
    myListA.remove(0);
    print_list(myListA);
    cout << "size:" << myListA.size() << endl;
    myListA.remove_if(equal_digit); //根据条件移除元素
    print_list(myListA);
    cout << "size:" << myListA.size() << endl;
    // unique 移除相同的元素
    myListA.assign(5, 1);
    print_list(myListA);
    cout << "size:" << myListA.size() << endl;
    myListA.unique();
    print_list(myListA);
    cout << "size:" << myListA.size() << endl;
    //sort 排序
    myListA.assign(intA, intA + 6);
    myListA.sort();
    print_list(myListA);
    cout << "size:" << myListA.size() << endl;
    //reverse 逆序
    myListA.reverse();
    print_list(myListA);
    cout << "size:" << myListA.size() << endl;
    //merge
    myListA.merge(myListC);
    print_list(myListA);
    cout << "size:" << myListA.size() << endl;
    return 0;
}