STL之list 【双向链表】

一、定义

list:双向链表,适用于频繁插入和删除元素的场景。

STL中的list是一种动态数组,也就是双向链表的数据结构,它具有以下特点:

  • 动态增长:当list中的元素数量超过当前容量时,它会自动增加容量。
  • 插入和删除:插入和删除元素的速度比数组快得多,因为它不需要移动元素。
  • 顺序访问:由于list是一个双向链表,因此可以从任意位置插入或删除元素,也可以按照顺序访问所有元素。
  • 逆序访问:由于list是一个双向链表,因此可以反向访问所有元素。

二、 数据结构

template <class T, class Allocator = allocator<T>>
class list
{
protected:
    struct _Node {           // Node代表链表中的一个节点
      T _Myval;             // 节点的数据域
      _Node* _Next;          // 指向前一个节点的指针
      _Node* _Prev;          // 指向后一个节点的指针
    };
    typedef _Node _Nodeptr;
    typedef typename Allocator::template rebind<_Node>::other _Alnode;
    _Alnode _Al;            // 链表的存储器分配器
    _Nodeptr _Myhead;         // 链表的第一个节点
    _Nodeptr _Mylast;         // 链表的最后一个节点
    size_type _Mysize;       // 链表中节点的数量
public:
    // 其他的成员函数...
};

//在这个结构中,_Nodeptr是一个内部类型,它是一个指针,指向_Node类型的对象。
//_Alnode也是一个内部类型,它是_Allocator类型的重新绑定,用来分配和释放节点的空间。
//_Myhead和_Mylast分别指向链表的第一个节点和最后一个节点,_Mysize表示链表中节点的数量。

三、具体使用

1.头文件:

#include <list>

2.创建list:

std::list<int> myList; // 创建一个整数类型的双向链表

3.插入元素:

使用 push_back()push_front() 方法在链表的末尾和开头插入元素:

myList.push_back(1); // 在链表末尾插入元素
myList.push_front(2); // 在链表开头插入元素 

插入指定位置:使用advance函数移动it迭代器,然后根据迭代器插入:

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

using namespace std;

int main() {
    list<int>  myList = { 1,2,3,4,5 };

    list<int>::iterator it = myList.begin();
    advance(it, 2);//将迭代器移动到索引2的位置
    myList.insert(it,30);

    // 遍历剩余的元素
    for (int value : myList) {
        cout << value << " ";
    }

    return 0;
}

插入元素

4.访问元素

使用迭代器可以访问链表中的元素:

std::list<int>::iterator it;
for (it = myList.begin(); it != myList.end(); ++it) {
    std::cout << *it << " ";
}

5.删除元素

使用 erase() 方法删除特定位置的元素:

myList.erase(myList.begin()); // 删除第一个元素
5.1 删除指定位置的元素:
#include <iostream>
#include <list>

int main() {
    list<int>  myList = { 1,2,3,4,5 };

    list<int>::iterator it = myList.begin();
    advance(it,2);//将迭代器移动到索引2的位置
    myList.erase(it);

    // 遍历剩余的元素
    for (int value : myList) {
        cout << value << " ";
    }

    return 0;
}    

删除元素

#include <iostream>
#include <vector>
#include <list>

using namespace std;

int main() {
    //1.创建双向链表list
    list<int> myList;

    //2.添加元素
    myList.push_back(5);
    myList.push_back(6);
    myList.push_back(7);
    myList.push_front(1);

    //3.使用迭代器遍历list
    //先声明一个遍历list的迭代器
    list<int>::iterator it;
    for (it = myList.begin(); it != myList.end();++it) {
        cout << *it << endl;
    }

    //4.删除元素
    myList.erase(myList.begin());//删除位置0的元素

    return 0;
}

综合示例:

在C++中管理动态数据集合时,std::list 可以是一个有用的容器。以下是一个使用 std::list 的示例,模拟了一个任务列表:

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

using namespace std;

struct Task {
    int id;
    string description;

    Task(int i, const string& desc) : id(i), description(desc) {}
};

int main() {
    list<Task> taskList;//用自定义Task数据结构创建list

    // 添加任务
    taskList.push_back(Task(1, "完成作业"));
    taskList.push_back(Task(2, "写报告"));
    taskList.push_back(Task(3, "购物"));
    taskList.push_back(Task(4, "锻炼"));

    // 遍历任务列表
    cout << "任务列表:" << endl;
    for (const Task& task : taskList) {
        cout << "Task " << task.id << ": " << task.description << endl;
    }

    // 完成任务
    list<Task>::iterator it = taskList.begin();
    while (it != taskList.end()) {
        if (it->id == 2) {
            it = taskList.erase(it); // 删除Task 2
        }
        else {
            ++it;
        }
    }

    cout << "\n更新后的任务列表:" << endl;
    for (const Task& task : taskList) {
        cout << "Task " << task.id << ": " << task.description << endl;
    }

    return 0;
}

其他常见操作

  • size(): 获取链表的大小。
  • empty(): 检查链表是否为空。
  • pop_back(): 移除链表末尾的元素。
  • pop_front(): 移除链表开头的元素。
  • splice(): 将一个链表的元素插入到另一个链表。
  • sort(): 对链表进行排序。
  • reverse(): 反转链表。

关注我,为大家持续分享更多的内容,让学习变得更简单,与君共勉,共同成长。 也可以关注我的公众号CoderSong,查看更多精彩文章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

西里小诸葛

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

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

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

打赏作者

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

抵扣说明:

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

余额充值