STL详解----list的使用

159 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

零.前言

学习了vector与string我们可以知道,所谓的STL就是将字符串,数组等数据结构进行严密地封装,方便我们直接使用而不需要进行临时创建,本节将介绍STL中的list,该类是对双向带头循环链表的使用。

1.list的介绍

list表示的是一个双向带头循环链表,允许在常数范围内的任意位置进行插入和删除,且前后可以进行双向迭代。其缺陷和链表一样就是不能支持随机访问(下标访问),但是在任意位置进行插入的效率更高。

2.创建变量

在创建变量之前别忘记包含list的头文件。

    list<int> l1;//创建一个空对象
    list<int> l2(3, 1);//创建一个包含3个1的对象
    list<int> l3(l2);//拷贝构造
    list<int> l4(l3.begin()++, l3.end()--);//在l3.begin()与l3.end()之间创造对象

注意由于l3是链表,因此不能将l3.begin()进行+1等操作。但是可以进行++,--的操作

3.遍历

与list和vector不同,list的遍历不能使用下标遍历,因为他是链表。 但我们可以使用迭代器进行遍历,这里的迭代器是双向迭代器,而不是像list和vector一样是随机迭代器。 双向迭代器的构造使其可以进行++等访问操作,在底层实际上就是操作符重载。

(1)迭代器遍历

    list<int>::iterator it = l3.begin();
    while (it != l3.end())
    {
        *it += 1;
        cout << *it<<" ";
        it++;
    }

同时也支持rbegin与rend,这里不予演示了。

(2)范围for遍历

    for (auto& e : l3)
    {
        cout << e << " ";
    }

使用范围for时,其底层也是迭代器,像vector一样传链表名即可。将迭代器类型改为reverse_iterator即可使用反向迭代器。反向迭代器在string详解中已经介绍过了。

4.list的大小

链表是插入元素,不需要进行提前扩容,因此没有reserve操作。我们可以使用empty来判空,使用size返回大小。

    cout << l1.empty() << endl;
    cout << l3.size() << endl;

在这里插入图片描述

5.插入删除

(1)头尾插删

我们可以使用push_back,push_front,pop_back,pop_front等进行插入和删除。

    l1.push_back(1);
    l1.push_back(2);
    l1.push_back(5);
    l1.push_back(3);
    l1.push_back(4);
    l1.push_front(6);
    l1.push_front(8);
    l1.pop_front();
    l1.pop_back();
    for (auto& e : l1)
    {
        cout << e << " ";
    }

在这里插入图片描述

(2)insert与erase

insert使用:

    auto pos = ++l1.begin();
    l1.insert(pos, 5);//pos位置前加15
    l1.insert(pos, 3, 5);//pos位置前加35
    l1.insert(pos, l3.begin(), l3.end());//将l3加到pos位置前
    for (auto& e : l1)
    {
        cout << e << " ";
    }
    

erase使用:

    l1.erase(pos);//删除pos位置元素
    l1.erase(++l1.begin(), --l1.end());//删除中间内容

在使用erase时要注意迭代器失效问题(迭代器指向节点被删除)。 在这里插入图片描述

6.交换,排序与清除

(1)排序

在vector中我们可以使用algorithm中的sort进行排序,而在list中只能使用list提供的sort,这是因为算法中的sort传参只能传随机迭代器,而list中是双向迭代器。 我们拿上方代码没erase的时候进行排序:

    l1.sort();
    for (auto& e : l1)
    {
        cout << e << " ";
    }

在这里插入图片描述 链表的排序效率过低,如果要排序尽量使用vector不要使用list。

(2)交换

将两个链表中内容进行交换的函数:

    l1.swap(l3);

在这里插入图片描述

(3)清除

清空链表中元素。

l1.clear();

在这里插入图片描述

7.总结

list的使用与vector基本一致,但是底层的实现却大相径庭,要真正理解list我们还需要多去阅读STL的源代码,可以尝试着模拟实现一下list类。

\