C++初阶之一篇文章教会你list(理解和使用)

在这里插入图片描述

list(理解和使用)

  • 什么是list
    • 特点和优势
    • 基本操作
    • 示例用法
    • 与其他序列式容器(如 std::vector 和 std::deque)相比,std::list 显著的区别和优势
    • 成员类型
  • list构造函数
    • 1. default (1)
    • 2. fill (2)
    • 3.range (3)
    • 4. copy (4)
  • list迭代器(Iterators)
    • 1. begin()
    • 2. end()
    • 3. rbegin()
    • 4. rend()
    • 5. cbegin()、cend()、crbegin()、crend()
  • list容量函数(Capacity)和元素访问函数(Element access)
    • 1. empty()
    • 2. size()
    • 3. max_size()
    • 4. front()
    • 5. back()
  • list增删查改函数(Modifiers)
    • 1. assign
    • 2. emplace_front
    • 3. push_front
    • 4. pop_front
    • 5. emplace_back
    • 6. push_back
    • 7. pop_back
    • 8. emplace
    • 9. insert
    • 10. erase
    • 11. swap
    • 12. resize
    • 13. clear
  • list操作函数(Operations)
    • 1. splice
    • 2. remove
    • 3. remove_if
    • 4. unique
    • 5. merge
    • 6. sort
    • 7. reverse
  • list的迭代器失效
  • 结语

什么是list

在这里插入图片描述

在C++标准库中,std::list 是一个双向链表容器,用于存储一系列元素。与 std::vectorstd::deque 等容器不同,std::list 使用链表的数据结构来组织元素,因此在某些操作上具有独特的优势和性能特点。以下是关于 std::list 的详细介绍:

特点和优势

双向链表结构: std::list 内部使用双向链表来存储元素。这意味着在插入和删除元素时,不会引起其他元素的内存重新分配和复制,因此在这些操作上具有常数时间复杂度。
插入和删除操作效率高: 由于链表结构,插入和删除元素的操作效率非常高。对于大量的插入和删除操作,std::list 往往比其他容器更具优势。
迭代器的稳定性:std::list 中,插入和删除元素不会使迭代器失效,除非删除的正是迭代器所指向的元素。这使得在遍历过程中进行插入和删除操作更加方便和安全。
空间占用: std::list每个元素都需要存储一个指向前后元素的指针,因此相对于数组型的容器,std::list 的空间占用会更高。

基本操作

push_back() push_front(): 在链表的末尾和开头插入元素。
pop_back() pop_front(): 删除链表的末尾和开头的元素。
insert(): 在指定位置插入元素。
erase(): 删除指定位置的元素。
begin()end(): 返回指向链表起始元素和尾部元素后一个位置的迭代器。
size(): 返回链表中的元素数量。
empty(): 检查链表是否为空。
clear(): 清空链表中的所有元素。

示例用法

#include <iostream>
#include <list>int main() {std::list<int> myList;myList.push_back(1);myList.push_back(2);myList.push_back(3);myList.pop_front();myList.insert(std::next(myList.begin()), 4);for (const auto& num : myList) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

在使用 std::list 时,需要权衡其优势和劣势,根据实际场景来选择合适的容器。当需要频繁插入和删除元素,且不需要随机访问时,std::list 可能是一个很好的选择。但需要注意的是,由于链表的特性,std::list 并不适用于需要快速随机访问元素的场景,因为访问某个位置的元素需要遍历链表。

与其他序列式容器(如 std::vector 和 std::deque)相比,std::list 显著的区别和优势

优势:

插入和删除效率高: 由于 std::list 是双向链表,插入和删除操作在常数时间内完成,不需要涉及内存的重新分配和元素的复制。这使得 std::list 在大量插入和删除操作时非常高效。
迭代器的稳定性: std::list 的插入和删除操作不会使迭代器失效,除非删除的正是迭代器所指向的元素。这使得在遍历过程中进行插入和删除操作更加方便和安全。
空间占用相对稳定: std::list 的空间占用相对稳定,插入和删除操作不会影响其他元素的空间占用。

劣势:

不支持随机访问: 由于链表的结构,std::list 不支持像数组一样的随机访问。访问某个位置的元素需要从链表的开头或结尾开始遍历。
额外的指针开销: std::list 中的每个元素都需要存储指向前后元素的指针,这使得空间占用相对其他容器更高。
缓存效率低: 由于链表中元素在内存中的存储位置不连续,导致在访问链表元素时,缓存命中率较低,可能影响性能。
迭代器的使用限制: std::list 的迭代器不支持与普通指针类似的算术操作(如 + 和 -),因此无法像 std::vector 那样灵活地进行迭代器操作。

在这里插入图片描述

成员类型

在这里插入图片描述

list构造函数

在这里插入图片描述
当使用 std::list 类创建对象时,可以使用不同的构造函数来满足不同的初始化需求。下面详细介绍每个构造函数及其使用示例:

1. default (1)

这个构造函数用于创建一个空的 std::list 容器。它可以接受一个可选的分配器参数,用于指定内存分配策略。

std::list<int> myList; // 创建一个空的 std::list 容器

2. fill (2)

这个构造函数用于创建一个包含 n 个元素的 std::list 容器,并将这些元素初始化为 val。你可以通过传递不同的 val 值来创建一个包含相同值的容器。同样,也可以传递一个可选的分配器参数。

std::list<int> myList(5, 42); // 创建一个包含 5 个元素,每个元素都是 42 的 std::list 容器

3.range (3)

这个构造函数使用迭代器范围 [first, last) 中的元素创建一个 std::list 容器。这使你可以通过一个迭代器范围来初始化容器。同样,它也接受一个可选的分配器参数。

std::vector<int> vec = {1, 2, 3, 4, 5};
std::list<int> myList(vec.begin(), vec.end()); // 从迭代器范围内的元素创建 std::list 容器

4. copy (4)

这个构造函数用于创建一个与已存在的 std::list 容器 x 相同的副本。它会将 x中的所有元素拷贝到新的容器中。这是一个拷贝构造函数。

std::list<int> originalList = {1, 2, 3, 4, 5};
std::list<int> copiedList(originalList); // 创建一个原容器的副本

这些构造函数提供了不同的初始化方式,以便根据具体需求来创建 std::list 容器。根据你的数据源和其他条件,选择适合的构造函数来创建容器对象。

list迭代器(Iterators)

1. begin()

iterator begin() noexcept;
这个版本的 begin() 返回一个迭代器,可以用于修改容器内的元素。noexcept 表示这个函数不会抛出异常。

std::list<int> myList = {1, 2, 3, 4, 5};
std::list<int>::iterator it = myList.begin(); // 获取可修改元素的迭代器
*it = 10; // 修改第一个元素的值为 10

const_iterator begin() const noexcept;
这个版本的 begin() 返回一个只读的迭代器,用于在不修改容器的情况下访问元素。const 表示这个函数不会修改容器。

const std::list<int> myList = {1, 2, 3, 4, 5};
std::list<int>::const_iterator cit = myList.begin(); // 获取只读元素的迭代器
int firstElement = *cit; // 读取第一个元素的值

2. end()

iterator end() noexcept;
这个版本的 end() 返回一个迭代器,可以用于修改容器内的元素。noexcept 表示这个函数不会抛出异常。这个迭代器指向的位置实际上是容器的末尾位置之后一个虚拟的位置,所以它并不指向容器内的任何元素。

std::list<int> myList = {1, 2, 3, 4, 5};
std::list<int>::iterator it = myList.end(); // 获取可修改元素的迭代器
--it; // 将迭代器前移一个位置,指向最后一个元素
*it = 20; // 修改最后一个元素的值为 20

const_iterator end() const noexcept;
这个版本的 end() 返回一个只读的迭代器,用于在不修改容器的情况下访问元素。const 表示这个函数不会修改容器。同样,这个迭代器也指向虚拟的位置,容器内的最后一个元素之后。

const std::list<int> myList = {1, 2, 3, 4, 5};
std::list<int>::const_iterator cit = myList.end(); // 获取只读元素的迭代器
--cit; // 将迭代器前移一个位置,指向最后一个元素
int lastElement = *cit; // 读取最后一个元素的值

3. rbegin()

reverse_iterator rbegin() noexcept;
这个版本的 rbegin() 返回一个反向迭代器,可以用于修改容器内的元素。noexcept 表示这个函数不会抛出异常。这个反向迭代器指向容器内的最后一个元素,可以通过递减操作符 -- 往前遍历容器。

std::list<int> myList = {1, 2, 3, 4, 5};
std::list<int>::reverse_iterator rit = myList.rbegin(); // 获取可修改元素的反向迭代器
*rit = 10; // 修改最后一个元素的值为 10
++rit; // 将反向迭代器往前移动一个位置,指向倒数第二个元素

const_reverse_iterator rbegin() const noexcept;
这个版本的 rbegin() 返回一个只读的反向迭代器,用于在不修改容器的情况下访问元素。const 表示这个函数不会修改容器。这个反向迭代器同样指向最后一个元素,可以通过递减操作符 -- 往前遍历容器。

const std::list<int> myList = {1, 2, 3, 4, 5};
std::list<int>::const_reverse_iterator crit = myList.rbegin(); // 获取只读元素的反向迭代器
int lastElement = *crit; // 读取最后一个元素的值
++crit; // 将反向迭代器往前移动一个位置,指向倒数第二个元素

4. rend()

reverse_iterator rend() nothrow;
这个版本的 rend() 返回一个反向迭代器,可以用于修改容器内的元素。nothrow 表示这个函数不会抛出异常。这个反向迭代器指向容器内的位置,位于第一个元素之前,可以通过递减操作符 -- 往前遍历容器。

std::list<int> myList = {1, 2, 3, 4, 5};
std::list<int>::reverse_iterator rit = myList.rend(); // 获取可修改元素的反向迭代器
--rit; // 将反向迭代器往前移动一个位置,指向最后一个元素
*rit = 10; // 修改最后一个元素的值为 10

const_reverse_iterator rend() const nothrow;
这个版本的 rend() 返回一个只读的反向迭代器,用于在不修改容器的情况下访问元素。const 表示这个函数不会修改容器。这个反向迭代器同样指向容器的位置,位于第一个元素之前,可以通过递减操作符 – 往前遍历容器。

const std::list<int> myList = {1, 2, 3, 4, 5};
std::list<int>::const_reverse_iterator crit = myList.rend(); // 获取只读元素的反向迭代器
--crit; // 将反向迭代器往前移动一个位置,指向最后一个元素
int lastElement = *crit; // 读取最后一个元素的值

5. cbegin()、cend()、crbegin()、crend()

const_iterator cbegin() const noexcept;
这个成员函数返回一个指向容器元素的常量迭代器,指向容器的起始位置。通过常量迭代器,你可以遍历容器的元素,但不能修改它们。

const_iterator cend() const noexcept;
这个成员函数返回一个指向容器元素的常量迭代器,指向容器的结束位置。这个迭代器表示一个超过容器尾部的位置,通常用于迭代器循环的终止条件。

std::list<int> myList = {1, 2, 3, 4, 5};
std::list<int>::const_iterator cit = myList.cbegin(); // 获取常量迭代器
for (; cit != myList.cend(); ++cit) {std::cout << *cit << " "; // 输出容器中的元素,不修改它们
}

const_reverse_iterator crbegin() const noexcept;
这个成员函数返回一个指向容器元素的常量反向迭代器,指向容器的反向起始位置。通过常量反向迭代器,你可以反向遍历容器的元素,但不能修改它们。

const_reverse_iterator crend() const noexcept;
这个成员函数返回一个指向容器元素的常量反向迭代器,指向容器的反向结束位置。这个迭代器表示一个超过容器首部的位置,通常用于反向迭代器循环的终止条件。

std::list<int> myList = {1, 2, 3, 4, 5};
std::list<int>::const_reverse_iterator crit = myList.crbegin(); // 获取常量反向迭代器
for (; crit != myList.crend(); ++crit) {std::cout << *crit << " "; // 反向输出容器中的元素,不修改它们
}

list容量函数(Capacity)和元素访问函数(Element access)

1. empty()

empty()std::list 容器的一个成员函数,用于判断容器是否为空。它返回一个布尔值,表示容器是否不包含任何元素。函数声明如下:

bool empty() const noexcept;

返回值:如果容器为空,则返回 true,否则返回 false。

使用示例

#include <iostream>
#include <list>int main() {std::list<int> myList;if (myList.empty()) {std::cout << "The list is empty." << std::endl;} else {std::cout << "The list is not empty." << std::endl;}myList.push_back(42);if (myList.empty()) {std::cout << "The list is empty." << std::endl;} else {std::cout << "The list is not empty." << std::endl;}return 0;
}

在上面的示例中,首先创建一个空的 std::list 容器 myList,然后使用 empty() 函数检查容器是否为空,并输出相应的信息。然后,通过 push_back 向容器中添加一个元素,并再次使用 empty() 函数检查容器是否为空,输出相应的信息。

2. size()

size()std::list 容器的一个成员函数,用于返回容器中元素的数量。它返回一个无符号整数类型,表示容器中的元素数量。函数声明如下:

size_type size() const noexcept;

返回值:返回容器中元素的数量,即大小。

使用示例

#include <iostream>
#include <list>int main() {std::list<int> myList;myList.push_back(1);myList.push_back(2);myList.push_back(3);std::cout << "Size of the list: " << myList.size() << std::endl;return 0;
}

在上面的示例中,我们首先创建一个 std::list 容器 myList,然后使用 push_back 函数向容器中添加三个元素。然后使用 size() 函数获取容器的大小,并输出到标准输出。

3. max_size()

max_size()std::list 容器的一个成员函数,用于返回容器可能容纳的最大元素数量,通常受到系统内存限制的影响。它返回一个无符号整数类型,表示容器的最大大小。函数签名如下:

size_type max_size() const noexcept;

返回值:返回容器可能容纳的最大元素数量。

使用示例

#include <iostream>
#include <list>int main() {std::list<int> myList;std::cout << "Max size of the list: " << myList.max_size() << std::endl;return 0;
}

在上面的示例中,我们创建了一个空的 std::list 容器 myList,然后使用 max_size() 函数获取容器的最大大小,并输出到标准输出。请注意,实际可用的最大大小取决于系统内存和其他资源的限制。

4. front()

front()std::list 容器的成员函数,用于返回容器中第一个元素的引用。这个函数有两个版本,一个用于可修改容器的对象,另一个用于只读(const)容器的对象。函数的签名如下:

reference front();
const_reference front() const;

reference:返回一个对容器中第一个元素的非常引用。
const_reference:只有在 const 容器对象上调用时,才返回一个对容器中第一个元素的常引用。

使用示例

#include <iostream>
#include <list>int main() {std::list<int> myList = {10, 20, 30};int& firstElement = myList.front();const int& constFirstElement = myList.front();std::cout << "First element: " << firstElement << std::endl;std::cout << "Const first element: " << constFirstElement << std::endl;return 0;
}

在上面的示例中,我们创建了一个 std::list 容器 myList,其中包含三个整数元素。我们使用 front() 函数来获取容器中的第一个元素的引用,分别存储为可修改的引用 firstElement 和只读的常引用 constFirstElement,然后将它们输出到标准输出。

5. back()

back() 是 std::list 容器的成员函数,用于返回容器中最后一个元素的引用。这个函数有两个版本,一个用于可修改容器的对象,另一个用于只读(const)容器的对象。函数的签名如下:

reference back();
const_reference back() const;

reference:返回一个对容器中最后一个元素的非常引用。
const_reference:只有在 const 容器对象上调用时,才返回一个对容器中最后一个元素的常引用。

使用示例

#include <iostream>
#include <list>int main() {std::list<int> myList = {10, 20, 30};int& lastElement = myList.back();const int& constLastElement = myList.back();std::cout << "Last element: " << lastElement << std::endl;std::cout << "Const last element: " << constLastElement << std::endl;return 0;
}

在上面的示例中,我们创建了一个 std::list 容器 myList,其中包含三个整数元素。我们使用 back() 函数来获取容器中的最后一个元素的引用,分别存储为可修改的引用 lastElement 和只读的常引用 constLastElement,然后将它们输出到标准输出。

list增删查改函数(Modifiers)

1. assign

assignstd::list 容器的成员函数,用于将容器的内容替换为新的元素。这个函数有三个不同版本:

使用迭代器范围:

template <class InputIterator>
void assign (InputIterator first, InputIterator last);

这个版本接受两个迭代器参数 firstlast,用来指定一个范围。它会将容器的内容替换为范围 [first, last) 内的元素。

使用重复元素:

void assign (size_type n, const value_type& val);
这个版本接受一个整数参数 n,和一个值 val。它会将容器的内容替换为 n 个值为 val 的元素。

使用初始化列表:

void assign (initializer_list<value_type> il);
这个版本接受一个初始化列表作为参数。它会将容器的内容替换为初始化列表中的元素。

使用示例:

#include <iostream>
#include <list>int main() {std::list<int> myList;myList.assign({1, 2, 3, 4, 5}); // 使用初始化列表std::cout << "Size after assigning with initializer list: " << myList.size() << std::endl;myList.assign(3, 100); // 使用重复元素std::cout << "Size after assigning with repeated elements: " << myList.size() << std::endl;std::list<int> anotherList = {10, 20, 30, 40};myList.assign(anotherList.begin(), anotherList.end()); // 使用迭代器范围std::cout << "Size after assigning with iterator range: " << myList.size() << std::endl;return 0;
}

在上面的示例中,我们首先创建了一个空的 std::list 容器 myList。然后使用不同版本的 assign 函数来分别替换容器的内容。最后,我们输出容器的大小以验证操作是否成功。

2. emplace_front

template <class... Args>
void emplace_front (Args&&... args);

emplace_frontstd::list 容器的成员函数,用于在容器的开头插入一个新元素。它通过在指定位置直接构造元素,避免了额外的拷贝或移动操作。

这个函数接受可变数量的参数 Args...,这些参数会被用来构造新元素。使用 emplace_front 可以直接在容器的开头插入元素,而不需要先创建一个临时对象然后再进行插入操作。

使用示例:

#include <iostream>
#include <list>struct Person {std::string name;int age;Person(const std::string& n, int a) : name(n), age(a) {std::cout << "Constructing " << name << std::endl;}
};int main() {std::list<Person> personList;personList.emplace_front("zhangsan", 25);personList.emplace_front("lisi", 30);personList.emplace_front("wangwu", 28);std::cout << "Person list contents:" << std::endl;for (const auto& person : personList) {std::cout << "Name: " << person.name << ", Age: " << person.age << std::endl;}return 0;
}

在上述示例中,我们首先定义了一个名为 Person 的结构体,它有两个成员变量:nameage。然后我们创建了一个空的 std::list 容器 personList,使用 emplace_front 函数分别在容器的开头插入了几个新的 Person 对象,直接在插入位置进行构造。

注意,emplace_front 的参数被传递给 Person 类型的构造函数,用于构造新的 Person 对象。这样做避免了额外的拷贝或移动操作,提高了效率。

3. push_front

push_frontstd::list 容器的成员函数,用于在容器的开头插入一个新元素。

这个函数有两个版本:

void push_front (const value_type& val);:接受一个常量引用参数,会创建一个新元素并将参数的值拷贝到新元素中。

void push_front (value_type&& val);:接受一个右值引用参数,用于移动构造一个新元素。这样可以避免额外的拷贝操作,提高了效率。

使用示例:

#include <iostream>
#include <list>int main() {std::list<int> myList;int value = 20;myList.push_front(value); // Copy insertstd::cout << "List contents:" << std::endl;for (const auto& num : myList) {std::cout << num << " ";}std::cout << std::endl;myList.push_front(25); // Move insertstd::cout << "List contents after move insert:" << std::endl;for (const auto& num : myList) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

在上述示例中,我们首先创建一个空的 std::list 容器 myList,然后使用 push_front 函数分别进行了常量引用拷贝插入和右值引用移动插入操作。可以看到,右值引用版本的 push_front 更加高效,因为它避免了额外的拷贝操作。

4. pop_front

void pop_front(); 是用于从 std::list 的开头移除一个元素的成员函数。它会删除列表中的第一个元素,并且将列表的大小减小一个单位。

示例用法:

std::list<int> myList = {1, 2, 3, 4, 5};
myList.pop_front(); // 移除第一个元素

在上面的例子中,pop_front() 将会移除 1 这个元素,使得列表变为 {2, 3, 4, 5}。

5. emplace_back

template <class... Args> void emplace_back (Args&&... args); 是一个用于在 std::list 的末尾插入新元素的函数。它允许你通过传递构造元素所需的参数来直接在列表的末尾构造元素,避免了额外的拷贝或移动操作。

示例用法:

std::list<std::string> myList;
myList.emplace_back("Hello");
myList.emplace_back("World");

在上面的例子中,emplace_back 函数直接在列表的末尾构造了两个字符串元素,分别是 "Hello""World"

这个函数对于避免额外的元素构造和拷贝操作很有用,特别是在容器中存储大型对象时,可以提高性能。

6. push_back

void push_back (const value_type& val);std::list 容器的成员函数,用于在列表的末尾插入一个新元素。它接受一个常量引用作为参数,将传入的值插入到列表末尾。

示例用法:

std::list<int> myList;
myList.push_back(10);
myList.push_back(20);
myList.push_back(30);

在上面的例子中,push_back 函数分别将整数 10、2030 插入到列表的末尾。

这个函数在操作上相对简单,但是可能涉及到内存分配和元素拷贝操作。如果插入的元素比较大,可能会导致额外的性能开销。

7. pop_back

void pop_back();std::list 容器的成员函数,用于删除列表中的最后一个元素。它会将列表的最后一个元素从容器中移除,同时释放相应的内存资源。

示例用法:

std::list<int> myList;
myList.push_back(10);
myList.push_back(20);
myList.push_back(30);myList.pop_back();

在上面的例子中,pop_back 函数会移除列表中的元素 30,使列表变为 [10, 20]

需要注意的是,调用 pop_back 函数前需要确保列表不为空,否则会出现未定义的行为。可以通过 empty() 函数来判断列表是否为空。

8. emplace

template <class... Args> iterator emplace (const_iterator position, Args&&... args);std::list 容器的成员函数,用于在指定位置插入一个新元素,并将元素构造函数的参数传递给插入的元素。

参数说明

position:要插入新元素的位置的迭代器。
args:传递给新元素构造函数的参数。
该函数返回一个迭代器,指向新插入的元素。

示例用法:

std::list<int> myList = {10, 20, 30};
auto it = myList.begin();
++it; // 移动到第二个元素的位置myList.emplace(it, 25); // 在第二个元素位置插入值为 25 的元素

在上面的例子中,emplace 函数在第二个元素的位置插入了一个值为 25 的新元素,使列表变为 [10, 25, 20, 30]。返回的迭代器指向插入的元素 25

这个函数适用于在任意位置插入元素,并且可以通过参数直接传递给元素的构造函数。

9. insert

iterator insert (iterator position, const value_type& val);
void insert (iterator position, size_type n, const value_type& val);
template <class InputIterator>
void insert (iterator position, InputIterator first, InputIterator last);

iterator insert (iterator position, const value_type& val); std::list 容器的成员函数,用于在指定位置插入一个新元素,新元素的值由 val 参数确定。

参数说明:

position:要插入新元素的位置的迭代器。
val:要插入的元素的值。
该函数返回一个迭代器,指向插入的元素。

示例用法:

std::list<int> myList = {10, 20, 30};
auto it = myList.begin();
++it; // 移动到第二个元素的位置myList.insert(it, 25); // 在第二个元素位置插入值为 25 的元素

void insert (iterator position, size_type n, const value_type& val); 是另一个版本的插入函数,可以插入指定数量的相同值的元素。

参数说明:

position:要插入新元素的位置的迭代器。
n:要插入的相同元素的数量。
val:要插入的元素的值。

template <class InputIterator> void insert (iterator position, InputIterator first, InputIterator last); 是另一个版本的插入函数,可以从指定范围的迭代器中插入一系列元素。

参数说明:

position:要插入新元素的位置的迭代器。
firstlast:要插入的元素范围的迭代器。

这些 insert 函数提供了不同的插入方式,使你可以根据需要灵活地向列表中添加元素。

10. erase

iterator erase (iterator position);iterator erase (iterator first, iterator last);std::list 容器的成员函数,用于从列表中删除一个或多个元素。

iterator erase (iterator position); 删除指定位置的元素,并返回指向下一个元素的迭代器。

参数说明:

position:要删除的元素的位置的迭代器。
返回值:指向被删除元素之后的元素的迭代器。

示例用法:

std::list<int> myList = {10, 20, 30, 40};
auto it = myList.begin();
++it; // 移动到第二个元素的位置myList.erase(it); // 删除第二个元素

iterator erase (iterator first, iterator last); 删除指定范围内的元素,并返回指向被删除范围之后的元素的迭代器。

参数说明:

firstlast:要删除的元素范围的迭代器,删除的范围包括 first,但不包括 last。
返回值:指向被删除范围之后的元素的迭代器。

示例用法:

std::list<int> myList = {10, 20, 30, 40};
auto it1 = myList.begin();
auto it2 = myList.begin();
std::advance(it2, 2); // 移动到第三个元素的位置myList.erase(it1, it2); // 删除第一个和第二个元素

这些函数允许你根据需要从列表中删除一个或多个元素,并返回正确的迭代器以便进行后续操作。

11. swap

void swap(list& x);std::list 容器的成员函数,用于交换当前列表与另一个列表 x 的内容。

参数说明:

x:要与当前列表进行内容交换的另一个列表。

示例用法:

#include <iostream>
#include <list>int main() {std::list<int> myList1 = {1, 2, 3};std::list<int> myList2 = {4, 5, 6};myList1.swap(myList2); // 交换两个列表的内容std::cout << "myList1: ";for (int num : myList1) {std::cout << num << " ";}std::cout << std::endl;std::cout << "myList2: ";for (int num : myList2) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

在上述示例中,myList1myList2 的内容被交换,导致输出中显示的内容分别为 4 5 61 2 3。这个函数对于在不同列表之间交换内容非常有用。

12. resize

void resize(size_type n, value_type val = value_type());std::list 容器的成员函数,用于调整列表的大小。

参数说明:

n:指定调整后的大小。
val:在列表扩展时,用于填充新元素的值。默认值为 value_type(),即类型的默认构造函数创建的值。
该函数通过在列表的末尾添加或删除元素,使列表的大小调整为指定的大小 n。如果新的大小大于当前大小,新元素将用指定的值 val 填充。如果新的大小小于当前大小,多余的元素将被删除。

示例用法:

#include <iostream>
#include <list>int main() {std::list<int> myList = {1, 2, 3, 4, 5};myList.resize(3); // 调整列表大小为3std::cout << "myList after resize to 3: ";for (int num : myList) {std::cout << num << " ";}std::cout << std::endl;myList.resize(5, 0); // 调整列表大小为5,并用0填充新元素std::cout << "myList after resize to 5 with filling 0: ";for (int num : myList) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

在上述示例中,首先调用 resize(3) 后,列表中只有前3个元素保留,然后调用 resize(5, 0) 后,列表中总共有5个元素,其中新添加的2个元素被填充为0

13. clear

void clear();std::list 容器的成员函数,用于清空列表中的所有元素,使列表变为空列表。

该函数会删除列表中的所有元素,使列表变为空,但并不会释放列表所占用的内存空间,所以列表的容量不会变化。这可以有效地回收元素所占用的资源,但保留容量可以减少频繁的内存分配和释放操作,以提高性能。

示例用法:

#include <iostream>
#include <list>int main() {std::list<int> myList = {1, 2, 3, 4, 5};std::cout << "myList before clear: ";for (int num : myList) {std::cout << num << " ";}std::cout << std::endl;myList.clear(); // 清空列表std::cout << "myList after clear: ";for (int num : myList) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

在上述示例中,首先输出了清空前的列表元素,然后调用 clear() 后,列表中的所有元素被删除,输出了清空后的列表元素,此时列表为空。

list操作函数(Operations)

1. splice

void splice (iterator position, list& x);
该成员函数用于将另一个列表 x 中的所有元素移动到当前列表中,插入到指定位置 position 前。x 列表在移动后会变为空列表。

示例用法:

#include <iostream>
#include <list>int main() {std::list<int> myList1 = {1, 2, 3};std::list<int> myList2 = {4, 5, 6};auto it = myList1.begin();std::advance(it, 2);myList1.splice(it, myList2); // 将 myList2 的元素插入到 myList1 中std::cout << "myList1 after splice: ";for (int num : myList1) {std::cout << num << " ";}std::cout << std::endl;std::cout << "myList2 after splice: ";for (int num : myList2) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

void splice (iterator position, list& x, iterator i);
该成员函数用于将另一个列表 x 中的元素移动到当前列表中,插入到指定位置 position 前,但只移动另一个列表 x 中的迭代器 i 指向的元素。

示例用法:

#include <iostream>
#include <list>int main() {std::list<int> myList1 = {1, 2, 3};std::list<int> myList2 = {4, 5, 6};auto it1 = myList1.begin();std::advance(it1, 1);auto it2 = myList2.begin();myList1.splice(it1, myList2, it2); // 将 myList2 中的第一个元素插入到 myList1 中std::cout << "myList1 after splice: ";for (int num : myList1) {std::cout << num << " ";}std::cout << std::endl;std::cout << "myList2 after splice: ";for (int num : myList2) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

void splice (iterator position, list& x, iterator first, iterator last);
该成员函数用于将另一个列表 x 中的一段元素范围 [first, last) 移动到当前列表中,插入到指定位置 position 前。

示例用法:

#include <iostream>
#include <list>int main() {std::list<int> myList1 = {1, 2, 3};std::list<int> myList2 = {4, 5, 6};auto it1 = myList1.begin();std::advance(it1, 1);auto it2_first = myList2.begin();auto it2_last = myList2.begin();std::advance(it2_last, 2);myList1.splice(it1, myList2, it2_first, it2_last); // 将 myList2 中的前两个元素插入到 myList1 中std::cout << "myList1 after splice: ";for (int num : myList1) {std::cout << num << " ";}std::cout << std::endl;std::cout << "myList2 after splice: ";for (int num : myList2) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

这些 splice 函数允许你在列表中移动元素,从一个列表中移动到另一个列表中,或在同一列表内重新排列元素的位置,而不需要进行元素的复制和删除。

2. remove

void remove (const value_type& val);
该成员函数用于从列表中移除所有等于给定值 val 的元素。

示例用法:

#include <iostream>
#include <list>int main() {std::list<int> myList = {1, 2, 3, 2, 4, 2, 5};myList.remove(2); // 移除列表中所有值为 2 的元素std::cout << "myList after remove: ";for (int num : myList) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

在示例中,myList 列表中的值为 2 的元素被移除,最终输出为 "1 3 4 5"

3. remove_if

template <class Predicate> void remove_if (Predicate pred);
这个成员函数用于根据给定的谓词函数 pred 移除满足特定条件的元素。

谓词函数 pred 接受一个参数并返回一个布尔值,用于判断是否需要移除该元素。如果谓词返回 true,则该元素将被移除。

示例用法:

#include <iostream>
#include <list>bool isEven(int num) {return num % 2 == 0;
}int main() {std::list<int> myList = {1, 2, 3, 4, 5, 6, 7, 8, 9};myList.remove_if(isEven); // 移除列表中所有偶数std::cout << "myList after remove_if: ";for (int num : myList) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

在示例中,myList 列表中的偶数元素被移除,最终输出为 "1 3 5 7 9"。函数 isEven 是一个谓词函数,用于判断是否为偶数

4. unique

void unique();
这个成员函数用于移除列表中相邻的重复元素。它只保留第一个出现的重复元素,移除后续的重复元素。

示例用法:

#include <iostream>
#include <list>int main() {std::list<int> myList = {1, 2, 2, 3, 4, 4, 4, 5};myList.unique(); // 移除相邻的重复元素std::cout << "myList after unique: ";for (int num : myList) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

在示例中,myList 列表中的相邻重复元素被移除,最终输出为 "1 2 3 4 5"

template <class BinaryPredicate> void unique (BinaryPredicate binary_pred);
这个成员函数在移除相邻重复元素时,使用自定义的二元谓词函数 binary_pred 来判断是否为重复元素。该谓词函数接受两个参数,并返回一个布尔值,用于判断两个元素是否相等。

示例用法:

#include <iostream>
#include <list>bool isEqual(int a, int b) {return a == b;
}int main() {std::list<int> myList = {1, 2, 2, 3, 4, 4, 4, 5};myList.unique(isEqual); // 使用 isEqual 判断是否为重复元素std::cout << "myList after unique with custom predicate: ";for (int num : myList) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

在示例中,通过自定义的谓词函数 isEqual 判断相邻的元素是否相等,移除相邻的重复元素,最终输出为 "1 2 3 4 5"

5. merge

void merge(list& x);
这个成员函数用于将另一个列表 x 合并到当前列表中,合并后的列表会按照升序排列。

示例用法:

#include <iostream>
#include <list>int main() {std::list<int> myList1 = {1, 3, 5};std::list<int> myList2 = {2, 4, 6};myList1.merge(myList2); // 将 myList2 合并到 myList1 中std::cout << "myList1 after merge: ";for (int num : myList1) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

在示例中,myList2 列表被合并到了 myList1 中,合并后的列表按照升序排列,最终输出为 "1 2 3 4 5 6"

template <class Compare> void merge(list& x, Compare comp);
这个成员函数与上面的 merge 函数类似,但是它允许提供一个自定义的比较函数 comp 来决定合并后的顺序。

示例用法:

#include <iostream>
#include <list>bool descendingOrder(int a, int b) {return a > b;
}int main() {std::list<int> myList1 = {5, 3, 1};std::list<int> myList2 = {6, 4, 2};myList1.merge(myList2, descendingOrder); // 使用自定义比较函数合并std::cout << "myList1 after merge with custom comparison: ";for (int num : myList1) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

在示例中,通过自定义的比较函数 descendingOrder,将 myList2 列表合并到了 myList1 中,合并后的列表按照降序排列,最终输出为 "6 5 4 3 2 1"

6. sort

void sort();
这个成员函数用于对列表进行升序排序,默认使用 < 运算符进行比较。

示例用法:

#include <iostream>
#include <list>int main() {std::list<int> myList = {5, 3, 1, 4, 2};myList.sort(); // 对列表进行升序排序std::cout << "myList after sorting: ";for (int num : myList) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

在示例中,列表中的元素经过排序后变为 "1 2 3 4 5"

template <class Compare> void sort(Compare comp);
这个成员函数与上面的 sort 函数类似,但是它允许提供一个自定义的比较函数 comp 来决定排序的顺序。

示例用法:

#include <iostream>
#include <list>bool descendingOrder(int a, int b) {return a > b;
}int main() {std::list<int> myList = {5, 3, 1, 4, 2};myList.sort(descendingOrder); // 使用自定义比较函数进行降序排序std::cout << "myList after custom sorting: ";for (int num : myList) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

在示例中,通过自定义的比较函数 descendingOrder,列表中的元素经过排序后变为 "5 4 3 2 1"

7. reverse

void reverse(); 函数用于将列表中的元素逆序排列。

示例用法:

#include <iostream>
#include <list>int main() {std::list<int> myList = {1, 2, 3, 4, 5};myList.reverse(); // 将列表中的元素逆序排列std::cout << "myList after reversing: ";for (int num : myList) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

在示例中,列表中的元素经过逆序排列后变为 "5 4 3 2 1"

list的迭代器失效

迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

当使用 std::list 进行删除操作时,可能会导致迭代器失效。下面是一个示例:

#include <iostream>
#include <list>int main() {std::list<int> myList = {1, 2, 3, 4, 5};auto it = myList.begin();++it; // Move the iterator to the second elementmyList.erase(it); // Erase the second elementfor (auto num : myList) {std::cout << num << " ";}return 0;
}

在上面的示例中,当我们在第二个元素位置处使用 erase 函数删除元素后,迭代器 it 就会失效,因为它指向的元素已经被删除。如果我们尝试使用失效的迭代器,可能会导致未定义的行为。

要修正这个问题,可以使用 erase 函数的返回值,它会返回一个指向下一个有效元素的迭代器:

#include <iostream>
#include <list>int main() {std::list<int> myList = {1, 2, 3, 4, 5};auto it = myList.begin();++it; // Move the iterator to the second elementit = myList.erase(it); // Erase the second element and update the iteratorfor (auto num : myList) {std::cout << num << " ";}return 0;
}

在这个修正后的示例中,我们使用 erase 函数的返回值更新了迭代器 it,以确保它指向的是有效的元素。这样就避免了使用失效迭代器引发的问题。

结语

有兴趣的小伙伴可以关注作者,如果觉得内容不错,请给个一键三连吧,蟹蟹你哟!!!
制作不易,如有不正之处敬请指出
感谢大家的来访,UU们的观看是我坚持下去的动力
在时间的催化剂下,让我们彼此都成为更优秀的人吧!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1382544.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

如何学习大数据

文章目录 每日一句正能量前言一、什么是大数据二、大数据的应用领域三、社会对大数据的人才需求四、大数据的学习路线后记 每日一句正能量 多数人认为&#xff0c;一旦达到某个目标&#xff0c;人们就会感到身心舒畅。但问题是你可能永远达不到目标。把快乐建立在还不曾拥有的事…

【雕爷学编程】Arduino动手做(54)---大按键微动按钮模块3

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

华为手机相册怎么镜像翻转_手机视频剪辑软件怎么制作电子相册_

2020年11月09日 10:25 作者&#xff1a;黄页 编辑&#xff1a;黄页 生活中我们经常会利用手机把身边的美好事物拍摄下来&#xff0c;用以记录生活中的点点滴滴。然而你是否想过将这些照片以动态的形式展示给身边的亲朋好友&#xff0c;让图片“动”起来呢?下面就教你手机视频剪…

华为堡垒机_浪潮无线分析,华为云堡垒机

预期结果步骤2在第6次输入错误用户名/密码时&#xff0c;页面无法正常打开&#xff0c;且被测设备有相关日志记录。测试结果口通过口部分通过口未通过口未测试备注4.2.16敏感数据泄密防护项目&#xff1a;Web攻击防护分项目&#xff1a;敏感数据泄密防护用例编号&#xff1a;版…

华为手机设置页面黑色_华为手机微信猫和老鼠主题皮肤怎么设置 ?超个性主题等你来设置!...

阅读本文前&#xff0c;请您先点击上面的蓝色字体&#xff0c;再点击“关注”&#xff0c;这样您就可以继续免费收到文章了。每天都有分享&#xff0c;完全是免费订阅&#xff0c;请放心关注。 …

华为手机大小尺寸一览_超实用!3招教你用华为手机玩转类型学摄影!

怎么样把照片发朋友圈最吸睛&#xff1f; 每个人都有展示图片的喜好和想法 但往往按照系列发一整组照片&#xff0c;容易收获更多点赞 ▼ 像这样我们常看到的系列图&#xff0c;有一个学名 叫做 “摄影类型学” 名字听起来有没有觉得很高级 但是操作起来却并不难 今天我们就来讲…

学以致用:python面向对象和PyEcharts的完美混合技

文章目录 学习目标数据案例分析数据内容需求分析参考代码data_define.pyfile_define.pymain.py 学习目标 使用面向对象思想完成数据读取和处理基于面向对象思想重新认知第三方库使用(PyEcharts) 数据案例分析 数据内容 1月份数据是普通文本&#xff0c;使用逗号分割数据记录&…

【力扣每日一题】2023.8.12 合并K个升序链表

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们一个链表数组&#xff0c;数组里的链表都是升序的&#xff0c;让我们合并这些链表&#xff0c;要求合并之后还是升序的。 最简…

【华为】IS-IS协议及配置

概念 中间系统到中间系统IS-IS(Intermediate System to Intermediate System&#xff09;属于内部网关协议IGP &#xff08;Interior Gateway Protocol)&#xff0c;用于自治系统内部。为了支持大规模的路由网络&#xff0c;IS-IS在自治系统内采用骨干区域与非骨干区域两级的分…

华为机试_HJ27 查找兄弟单词【中等】

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 解题过程 提交代码 学习代码 代码一 收藏点 描述 定义一个单词的“兄弟单词”为&#xff1a;交换该单词字母顺序&#xff08;注&#xff1a;可以交换任意次&#xff09;&#xff0c;而不添加、删除、修改原有的字…

NR700 —基础知识

01 中国5G频段分布及700M频谱 中国运营商频段分布&#xff1a; 不同频段的无线电波的特征&#xff1a; 700M网络因其低频特性&#xff0c;有着极佳的覆盖能力和穿透能力&#xff0c;但同时相对运营商已有的高频网络有着明显的性能差距。因此700M网络更适合用于底层网络深度覆盖…

大数据Flink(六十一):Flink流处理程序流程和项目准备

文章目录 Flink流处理程序流程和项目准备 一、Flink流处理程序的一般流程

又一款 IDEA 全家桶 神器 ja-netfilter-all 插件

又一款 IDEA 全家桶 神器 ja-netfilter-all 文章目录 许可证代码&#xff1a;许可证服务器&#xff1a;新的&#xff1a;idea vmoptions 配置验证 ja-netfilter 是否配置成功出现如下 日志信息 为 配置成功 提示 临时码总结 C站下载地址&#xff1a; https://download.csdn.net…

global::System.Runtime.Versioning.TargetFrameworkAttribute 特性重复

visual studio code 反编译 报错 global::System.Runtime.Versioning.TargetFrameworkAttribute”特性重复 在 .csproj文件内添加 <PropertyGroup><GenerateAssemblyInfo>false</GenerateAssemblyInfo><GenerateTargetFrameworkAttribute>false</G…

Load balancer does not have available server for client

com.netflix.client.ClientException: Load balancer does not have available server for client: ***** 在使用openfeign作为负载客户端调用时&#xff0c;抛出异常: 解决办法&#xff1a; 在application.yml配置文件中添加 ribbon:eureka:enabled: true

无法安装程序包“xx”。你正在尝试将此程序包安装到目标为“.NETFramework,Version=v4.0”的项目中,但该程序包不包含任何与该框架兼容的程序集引用或内容文件。

打开一个之前的项目并重新启动时&#xff0c;无法正确生成&#xff0c;提示CefSharp没有安装&#xff1a; error CS0246: The type or namespace name CefSharp could not be found (are you missing a using directive or an assembly reference?) 于是乎卸载之前的版本重新…

系列二、idea启动springboot工程报错

一、报错信息 二、解决方法 2.1、打开工程.idea目录的workspace.xml文件 2.2、找到PropertiesComponent标签 2.3、添加一行 2.4、添加的内容 <property name"dynamic.classpath" value"true" />

关于SpringCloud-zuul 报错:Caused by: com.netflix.client.ClientException: Load balancer does not have ava

描述 最近在学习SpringCloud微服务&#xff0c;使用路由网关zuul;在使用过程中遇到问题报错了&#xff1b; Caused by: com.netflix.client.ClientException: Load balancer does not have available server for client: api1at com.netflix.loadbalancer.LoadBalancerContex…

Spring Cloud Eureka注册不成功

下面我介绍我总结的&#xff08;主要2点&#xff09; 1.启动类未加注解 服务注册中心 EnableEurekaServer 服务提供 EnableEurekaClient 2.检查自己pom依赖是否导入错误 <!--容易倒错依赖--> spring-cloud-netflix-eureka-server <!--正确依赖--> spring-cloud…

win10怎么安装 .net framework 3.5

复制链接&#xff1a;http://download.windowsupdate.com/d/msdownload/update/software/updt/2015/11/microsoft-windows-netfx3-ondemand-package_421a25bf409692045d1cbfab0d99f8def8d95d3f.cab 将下载的文件复制到复制到 C 盘的 Windows 文件夹 后请在“命令提示符&#x…