【C++】list的使用(下)

简介: 这篇博客探讨了C++ STL中`list`容器的几个关键操作,包括`splice()`、`remove()`、`remove_if()`和`unique()`。`splice()`允许高效地合并或移动`list`中的元素,无需构造或销毁。`remove()`根据值删除元素,而`remove_if()`则基于谓词移除元素。`unique()`则去除连续重复的元素,可选地使用自定义比较函数。每个操作都附带了代码示例以说明其用法。

前言

本篇博客主要内容:STL库中list用法的讲解

让我们接着上一篇博文的内容继续,进入list最后一个模块,操作list对象的接口函数。

🔥操作list对象的接口函数(opeartions)

在这里插入图片描述

==splice==

在这里插入图片描述

从x中转移元素到容器中,并将它们插入到指定的位置(功能相当于剪切)。

这实际上是将这些元素插入到容器中,并从x中移除它们,从而改变两个容器的大小。这个操作不涉及任何元素的构造或销毁。元素被转移,无论x是左值还是右值,或者value_type是否支持移动构造。

entire list (1)

void splice (iterator position, list& x);

single element (2)

void splice (iterator position, list& x, iterator i);

element range (3)

void splice (iterator position, list& x, iterator first, iterator last);

第一个版本(1)将x中的所有元素转移到容器中position指向的元素之前。
第二个版本(2)仅将x中由i指向的元素转移到容器中position指向的元素之前。
第三个版本(3)将x中迭代器范围[first,last)中的元素转移到容器中position指向的元素之前。

代码案例:

// splicing lists
#include <iostream>
#include <list>

int main ()
{
   
   
  std::list<int> mylist1, mylist2;
  std::list<int>::iterator it;

  // set some initial values:
  for (int i=1; i<=4; ++i)
     mylist1.push_back(i);      // mylist1: 1 2 3 4

  for (int i=1; i<=3; ++i)
     mylist2.push_back(i*10);   // mylist2: 10 20 30

  it = mylist1.begin();
  ++it;                         // 迭代器指向 2

  mylist1.splice (it, mylist2); // mylist1: 1 10 20 30 2 3 4
                                // mylist2 (empty)
                                // "it" 迭代器仍然指向 2 (第五个元素)

  mylist2.splice (mylist2.begin(),mylist1, it);
                                // mylist1: 1 10 20 30 3 4
                                // mylist2: 2
                                // "it"迭代器现在失效了
  it = mylist1.begin();
  std::advance(it,3);           // "it" 迭代器现在指向 30

  mylist1.splice ( mylist1.begin(), mylist1, it, mylist1.end());
                                // mylist1: 30 3 4 1 10 20

  std::cout << "mylist1 contains:";
  for (it=mylist1.begin(); it!=mylist1.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  std::cout << "mylist2 contains:";
  for (it=mylist2.begin(); it!=mylist2.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

在这里插入图片描述

==remove==

在这里插入图片描述

void remove (const value_type& val);

该函数(list::remove)从容器中移除所有与给定值val相等的元素。这会调用这些对象的析构函数,并通过移除的元素数量来减少容器的大小。

与成员函数list::erase不同,list::erase是通过元素的位置(使用迭代器)来删除元素的,而list::remove则是通过元素的值来删除元素的。

还存在一个类似的函数list::remove_if,它允许通过除了相等性比较之外的条件来确定是否移除一个元素。

代码案例:

// remove from list
#include <iostream>
#include <list>

int main()
{
   
   
    int myints[] = {
   
    17,89,7,14 };
    std::list<int> mylist(myints, myints + 4);

    mylist.remove(89);

    std::cout << "mylist contains:";
    for (std::list<int>::iterator it = mylist.begin(); it != mylist.end(); ++it)
        std::cout << ' ' << *it;
    std::cout << '\n';

    return 0;
}

在这里插入图片描述

==remove_if==

在这里插入图片描述

template <class Predicate>
  void remove_if (Predicate pred);

该函数从容器中移除所有使得所给定谓词(Predicate)pred返回true的元素。这会调用这些对象的析构函数,并通过移除的元素数量来减少容器的大小。

对于容器中的每个元素(其中i是指向该元素的迭代器),该函数会调用pred(*i)。列表中任何使得pred(*i)返回true的元素都将从容器中移除。

pred:可以是一个函数指针函数对象,它接受一个与forward_list对象中元素类型相同的值,并返回一个布尔值。对于要从容器中移除的值,该谓词返回true;对于保留在容器中的值,返回false。这样,你可以通过提供一个这样的谓词来定制forward_list中元素的移除规则。

代码案例:

// list::remove_if
#include <iostream>
#include <list>

// 函数:
bool single_digit(const int& value) {
   
    return (value < 10); }

// 仿函数,一个类伪装成的函数:
struct is_odd {
   
   
    bool operator() (const int& value) {
   
    return (value % 2) == 1; }
};

int main()
{
   
   
    int myints[] = {
   
    15,36,7,17,20,39,4,1 };
    std::list<int> mylist(myints, myints + 8);   // 15 36 7 17 20 39 4 1

    mylist.remove_if(single_digit);           // 15 36 17 20 39

    mylist.remove_if(is_odd());               // 36 20

    std::cout << "mylist contains:";
    for (std::list<int>::iterator it = mylist.begin(); it != mylist.end(); ++it)
        std::cout << ' ' << *it;
    std::cout << '\n';

    return 0;
}

在这里插入图片描述

==unique==

在这里插入图片描述
(1)

void unique();

(2)

template <class BinaryPredicate>
  void unique (BinaryPredicate binary_pred);

没有参数的版本(1)会移除容器中每个连续相等元素组中除了第一个元素以外的所有元素

请注意,当一个元素只有当它与它前面紧挨着的元素相等时,才会从列表中移除。因此,这个函数特别适用于已排序的列表

第二个版本(2)接受一个特定的比较函数作为参数,用于确定元素的“唯一性”。实际上,可以实现任何行为(而不仅仅是相等性比较),但请注意,该函数会对所有元素对(其中i是元素迭代器,从第二个元素开始)调用binary_pred(*i,*(i-1)),如果谓词返回true,则将i从列表中移除。

被移除的元素的空间会被释放。

代码案例:

// list::unique
#include <iostream>
#include <cmath>
#include <list>

// a binary predicate implemented as a function:
bool same_integral_part(double first, double second)
{
   
   
    return (int(first) == int(second));
}

// a binary predicate implemented as a class:
struct is_near {
   
   
    bool operator() (double first, double second)
    {
   
   
        return (fabs(first - second) < 5.0);
    }
};

int main()
{
   
   
    double mydoubles[] = {
   
    12.15,  2.72, 73.0,  12.77,  3.14,
                         12.77, 73.35, 72.25, 15.3,  72.25 };
    std::list<double> mylist(mydoubles, mydoubles + 10);

    mylist.sort();             //  2.72,  3.14, 12.15, 12.77, 12.77,
    // 15.3,  72.25, 72.25, 73.0,  73.35

    mylist.unique();           //  2.72,  3.14, 12.15, 12.77
    // 15.3,  72.25, 73.0,  73.35

    mylist.unique(same_integral_part);  //  2.72,  3.14, 12.15
    // 15.3,  72.25, 73.0

    mylist.unique(is_near());           //  2.72, 12.15, 72.25

    std::cout << "mylist contains:";
    for (std::list<double>::iterator it = mylist.begin(); it != mylist.end(); ++it)
        std::cout << ' ' << *it;
    std::cout << '\n';

    return 0;
}

在这里插入图片描述

相关文章
|
2天前
|
存储 编译器 C语言
【C++】list模拟实现
本文档介绍了C++ STL中`list`容器的模拟实现,包括`ListNode`节点类、迭代器类和`list`类的详细设计。`ListNode`模板类存储数据并维护前后指针;`ListIterator`是一个复杂的模板类,提供解引用、自增/自减以及比较操作。`list`类包含了链表的各种操作,如插入、删除、访问元素等,并使用迭代器作为访问接口。实现中,迭代器不再是简单的指针,而是拥有完整功能的对象。此外,文档还提到了迭代器的实现对C++语法的特殊处理,使得`it-&gt;_val`的写法成为可能。文章通过分步骤展示`list`的各个组件的实现,帮助读者深入理解STL容器的内部工作原理。
|
2天前
|
算法 搜索推荐 C++
【C++】list的使用(下)
`C++` 中 `std::list` 的 `merge()`、`sort()` 和 `reverse()` 操作: - `merge(x)` 和 `merge(x, comp)`: 合并两个已排序的`list`,将`x`的元素按顺序插入当前`list`,`x`清空。比较可自定义。 - `sort()` 和 `sort(comp)`: 对`list`元素排序,保持等价元素相对顺序。内置排序基于稳定排序算法,速度较慢。 -reverse(): 反转`list`中元素的顺序。 这些操作不涉及元素构造/销毁,直接移动元素。注意,`sort()`不适合`std::list`,因链表结构不利于快速排序
|
2天前
|
编译器 C++ 容器
【C++】list的使用(上)
迭代器在STL中统一了访问接口,如`list`的`begin()`和`end()`。示例展示了如何使用正向和反向迭代器遍历`list`。注意`list`的迭代器不支持加减操作,只能用`++`和`--`。容器的`empty()`和`size()`用于检查状态和获取元素数。`front()`和`back()`访问首尾元素,`assign()`重载函数用于替换内容,`push_*/pop_*`管理两端元素,`insert()`插入元素,`erase()`删除元素,`resize()`调整大小,`clear()`清空容器。这些接口与`vector`和`string`类似,方便使用。
|
3天前
|
存储 C++
C++的list-map链表与映射表
```markdown C++ 中的`list`和`map`提供链表和映射表功能。`list`是双向链表,支持头尾插入删除(`push_front/push_back/pop_front/pop_back`),迭代器遍历及任意位置插入删除。`map`是键值对集合,自动按键排序,支持直接通过键来添加、修改和删除元素。两者均能使用范围for循环遍历,`map`的`count`函数用于统计键值出现次数。 ```
13 1
|
11天前
|
编译器 C++ 容器
【C++/STL】:list容器的深度剖析及模拟实现
【C++/STL】:list容器的深度剖析及模拟实现
13 2
|
14天前
|
存储 算法 C++
C++一分钟之-容器概览:vector, list, deque
【6月更文挑战第21天】STL中的`vector`是动态数组,适合随机访问,但插入删除非末尾元素较慢;`list`是双向链表,插入删除快但随机访问效率低;`deque`结合两者优点,支持快速双端操作。选择容器要考虑操作频率、内存占用和性能需求。注意预分配容量以减少`vector`的内存重分配,使用迭代器而非索引操作`list`,并利用`deque`的两端优势。理解容器内部机制和应用场景是优化C++程序的关键。
25 5
|
10天前
|
编译器 C语言 C++
C++ STL中list迭代器的实现
C++ STL中list迭代器的实现
C++ STL中list迭代器的实现
|
11天前
|
存储 C++ 容器
【C++/STL】:list容器的基本使用
【C++/STL】:list容器的基本使用
11 1
|
2天前
|
存储 编译器 C语言
【C++】list的使用(上)
**C++ STL的list是一个基于双向循环链表的容器,支持常数时间内插入和删除,但不支持随机访问。默认构造函数、填充构造、迭代器范围构造和拷贝构造提供多种初始化方式。析构函数自动释放内存,赋值运算符重载用于内容替换。示例代码展示了构造和赋值操作。**
|
2天前
|
存储 算法 程序员
C++基础知识(八:STL标准库(Vectors和list))
C++ STL (Standard Template Library标准模板库) 是通用类模板和算法的集合,它提供给程序员一些标准的数据结构的实现如 queues(队列), lists(链表), 和 stacks(栈)等. STL容器的提供是为了让开发者可以更高效率的去开发,同时我们应该也需要知道他们的底层实现,这样在出现错误的时候我们才知道一些原因,才可以更好的去解决问题。