全面理解:C++中list(双向链表)容器的基础概念与函数解析

list容器的基础概念

在 C++ 标准库中,list 是一种双向链表,允许在任何位置进行快速的插入和删除操作。

以下是一些关于 list 的基本信息。

  • 存储:list 是一种双向链表结构,它不像 vector 或 array 那样提供连续的内存存储。

  • 时间复杂度list 在链表的开始、结束或中间位置插入和删除元素的时间复杂度是 O(1)。然而,查找元素的时间复杂度是 O(n)。

  • 空间复杂度:由于链表中每个元素都需要额外存储其前后节点的信息,因此 list 相比于使用连续内存的容器(如 vector 或 array)具有更高的空间复杂度。

  • 迭代器失效当你插入或删除元素时,list 的所有迭代器,包括指向链表开始和结束位置的迭代器,都不会失效。唯一的例外是当你删除一个元素时,指向该元素的迭代器将失效

  • 元素访问list 不支持随机访问。要访问 list 中的元素,你必须从链表的开始(或结束)位置遍历到你要访问的位置。因此,list 不提供 operator[] 函数(下标运算符)

list的函数解析

  • list有各种各样的成员函数,下面我将以函数的功能对这些函数分一下类,然后按照类别,一一介绍这些函数的用处。

构造函数

  • list(): 创建一个空的 list
  • list(n, elem): 创建一个包含 n 个元素的 list,每个元素的值都是 elem
  • list(begin, end): 创建一个包含 [begin, end) 区间元素的 list

以下是使用这些构造函数创建 std::list 的示例:

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

int main() {
    // 创建一个空的 list
    std::list<int> list1;

    // 创建一个包含 5 个元素的 list,每个元素的值都是 10
    std::list<int> list2(5, 10);

    // 从 vector 创建 list
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::list<int> list3(vec.begin(), vec.end());

    // 打印 list2
    for(int i : list2) {
        std::cout << i << " ";
    }
    std::cout << "\n";

    // 打印 list3
    for(int i : list3) {
        std::cout << i << " ";
    }

    return 0;
}

元素访问函数

  • front(): 返回首元素
  • back(): 返回尾元素

注意:这里是返回的是链表的元素,而不是指向元素的迭代器或指针

各种迭代器函数

  • begin(): 返回指向首元素的迭代器
  • end(): 返回指向尾元素的下一个位置的迭代器
  • rbegin(): 返回指向尾元素的反向迭代器
  • rend(): 返回指向首元素的前一个位置的反向迭代器

在这里我想详细讲解一下这个迭代器

  • 你可以把list的这个这个迭代器,详细成一个高级的指针。
  • 迭代器是一个对象(指针),假如说list里面的节点元素都是一个个的值了话,这个迭代器就是一个指向这个值的一个指针罢了。我们就可以用解引用符 * 去修改这个值。
  • 假如说迭代器指向的这个对象它是一个类,或者是一个结构体,它有成员变量,那你就可以用箭头符 -> 去操作这个对象的成员变量。你可以把这个对象想象成你自己定义的Listnode,你用箭头符去操作它,hh

判断容器容量函数:

  • empty(): 判断容器是否为空
  • size(): 返回容器中元素的个数
  • max_size(): 返回容器能够容纳的最大元素数量

添加操作

  • insert(position, elem): 在 position 位置前插入一个元素
  • push_back(elem): 在 list 的尾部添加一个元素
  • push_front(elem): 在 list 的头部添加一个元素

删除操作

  • clear(): 删除所有元素
  • erase(position): 删除 position 位置的元素
  • pop_back(): 删除 list 尾部的一个元素
  • pop_front(): 删除 list 头部的一个元素
  • unique(): 删除所有相邻重复元素
  • remove_if(predicate): 删除满足条件 predicate 的所有元素
  • remove(elem): 删除所有值为 elem 的元素

修改容器大小的函数

  • resize(size, elem): 改变容器的大小,如果需要添加元素,则元素值为 elem

具体讲解一下splice()这个函数

splice() 是list 的一个非常有用的成员函数,它可以高效地将元素从一个列表移到另一个列表,或者从列表的一个位置移动到另一个位置因为它是重新链接节点指针,不会导致元素内容的复制或移动,所以速度非常快。它一共有三种重载版本。

三种重载版本如下:

  • void splice (const_iterator position, list& x);

    • 将 x 中的所有元素移到当前列表的 position 位置。 x 变为空。
  • void splice (const_iterator position, list& x, const_iterator i);

    • 将 x 中的元素 i 移到当前列表的 position 位置。 i 在 x 中的元素被移除。
  • void splice (const_iterator position, list& x, const_iterator first, const_iterator last);

    • 将 x 中的 [first, last) 区间的元素移到当前列表的 position 位置。 这个区间在 x 中的元素被移除。

    • 注意:position 和 x 可以指向同一个列表,但 position 不能在 [first, last) 区间内。

下面是使用 splice() 的例子:

#include <iostream>
#include <list>

int main() {
    std::list<int> list1 = {1, 2, 3};
    std::list<int> list2 = {4, 5, 6};

    // move all elements of list2 to list1
    list1.splice(list1.end(), list2);

    std::cout << "list1: ";
    for (int num : list1) {
        std::cout << num << " ";
    }
    std::cout << "\n";

    std::cout << "list2: ";
    for (int num : list2) {
        std::cout << num << " ";
    }
    std::cout << "\n";

    // move back one element from list1 to list2
    list2.splice(list2.begin(), list1, --list1.end());

    std::cout << "list1: ";
    for (int num : list1) {
        std::cout << num << " ";
    }
    std::cout << "\n";

    std::cout << "list2: ";
    for (int num : list2) {
        std::cout << num << " ";
    }
    std::cout << "\n";

    return 0;
}

在这个例子中,我们首先创建了两个列表。然后,我们将 list2 中的所有元素移动到 list1 的尾部。接着,我们将 list1 的最后一个元素移动到 list2 的头部。每次操作后,我们都打印出两个列表的内容。

交换元素的函数

  • swap(list): 交换两个 list

反转链表函数

  • reverse(): 反转 list

对链表进行排序的函数

  • sort(): 排序 list

这是一些使用 list 的示例:

#include <iostream>
#include <list>

int main() {
    std::list<int> numbers;

    // push elements
    numbers.push_back(5);
    numbers.push_back(10);
    numbers.push_front(1);

    // iterate through the list
    for(std::list<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) {
        std::cout << *it << ' ';
    }
    std::cout << '\n';

    // remove an element
    numbers.remove(1);

    for(auto &num : numbers) {
        std::cout << num << ' ';
    }
    std::cout << '\n';

    // sort the list
    numbers.sort();

    for(auto &num : numbers) {
        std::cout << num << ' ';
    }
    std::cout << '\n';

    return 0;
}

这段代码首先创建了一个空的 list,然后在尾部和头部添加了一些元素。然后它通过迭代器遍历 list 并打印每个元素。然后它删除一个元素,并再次打印 list。最后,它对 list 进行排序,并打印排序后的 list。

总结

  • 在C++标准库中,list是一种双向链表,允许在任何位置进行快速的插入和删除操作。list在任何位置插入和删除元素都有相对稳定的性能,而不是依赖于元素在容器中的位置。

  • 我们讨论了list的多种构造函数,包括默认构造函数、初始化列表构造函数、以及从其他容器复制元素的构造函数。

  • 我们也介绍了 splice() 函数,这是一个非常有用的成员函数,它可以高效地将元素从一个列表移到另一个列表。splice()有三种重载版本,它们都不会导致元素内容的复制或移动,而是重新链接节点指针,因此速度非常快。

最后,我们讨论了一些其他的std::list成员函数,包括元素访问、迭代器、容量查询、列表修改和操作等。

最后的最后,如果你觉得我的这篇文章写的不错的话,请给我一个赞与收藏,关注我,我会继续给大家带来更多更优质的干货内容

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

阿宋同学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值