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

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

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); // 调整列表大小为3
    std::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 element
    myList.erase(it); // Erase the second element
    for (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 element
    it = myList.erase(it); // Erase the second element and update the iterator
    for (auto num : myList) {
        std::cout << num << " ";
    }
    return 0;
}

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

结语

有兴趣的小伙伴可以关注作者,如果觉得内容不错,请给个一键三连吧,蟹蟹你哟!!!

制作不易,如有不正之处敬请指出

感谢大家的来访,UU们的观看是我坚持下去的动力

在时间的催化剂下,让我们彼此都成为更优秀的人吧!!!


相关文章
|
7天前
|
算法 C语言 C++
【c++丨STL】list的使用
本文介绍了STL容器`list`的使用方法及其主要功能。`list`是一种双向链表结构,适用于频繁的插入和删除操作。文章详细讲解了`list`的构造函数、析构函数、赋值重载、迭代器、容量接口、元素访问接口、增删查改操作以及一些特有的操作接口如`splice`、`remove_if`、`unique`、`merge`、`sort`和`reverse`。通过示例代码,读者可以更好地理解如何使用这些接口。最后,作者总结了`list`的特点和适用场景,并预告了后续关于`list`模拟实现的文章。
22 7
|
16天前
|
存储 编译器 C++
C++ initializer_list&&类型推导
在 C++ 中,`initializer_list` 提供了一种方便的方式来初始化容器和传递参数,而右值引用则是实现高效资源管理和移动语义的关键特性。尽管在实际应用中 `initializer_list&&` 并不常见,但理解其类型推导和使用方式有助于深入掌握现代 C++ 的高级特性。
16 4
|
2月前
|
存储 搜索推荐 C++
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
62 2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
|
2月前
|
存储 算法 C++
【C++打怪之路Lv10】-- list
【C++打怪之路Lv10】-- list
23 1
|
2月前
|
存储 C++ 容器
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器1
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
68 5
|
2月前
|
存储 编译器 C++
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
78 2
|
2月前
|
C++
【C++】C++ STL 探索:List使用与背后底层逻辑(三)
【C++】C++ STL 探索:List使用与背后底层逻辑
|
2月前
|
C++
【C++】C++ STL 探索:List使用与背后底层逻辑(二)
【C++】C++ STL 探索:List使用与背后底层逻辑
|
2月前
|
存储 编译器 C++
【C++】C++ STL 探索:List使用与背后底层逻辑(一)
【C++】C++ STL 探索:List使用与背后底层逻辑
|
2月前
|
存储 缓存 C++
C++番外篇——list与vector的比较
C++番外篇——list与vector的比较
26 0