List

列表 (list) 简介

列表 (list) 是一种线性数据结构,这意味着列表中的元素排列成一个序列。每个元素在列表中都有一个确定的位置,并且元素之间存在着先后关系。

在计算机科学中,列表通常通过链表 (linked list) 的方式来实现。链表是一种由一系列节点组成的数据结构。每个节点包含两部分:

  • 数据 (information/info):用于存储实际的元素值。
  • 指针 (pointer/next):指向列表中的下一个节点。对于双向链表 (doubly linked list),每个节点还会包含一个指向前一个节点的指针 (prev)。

链表有多种变体:

  • 单向链表 (singly linked list):每个节点只有一个指向下一个节点的指针。要访问链表中的元素,通常需要从头节点 (head) 开始遍历。
  • 双向链表 (doubly linked list):每个节点有两个指针,一个指向下一个节点,一个指向上一个节点。这使得在列表中进行双向遍历更为方便。
  • 循环链表 (circular list):最后一个节点的指针指向头节点,形成一个环。循环链表可以是单向的也可以是双向的。

链表与数组等其他线性数据结构相比,具有以下特点

  • 动态性:链表的大小可以在运行时动态地增加或减少,因为节点可以在需要时被分配或释放。
  • 插入和删除效率高:在链表的任意位置插入或删除一个节点通常只需要修改相邻节点的指针,时间复杂度为 O(1) (假设已知要插入或删除的位置)。
  • 随机访问效率低:要访问链表中特定位置的元素,通常需要从头节点开始遍历,直到找到目标位置,时间复杂度为 O(n),其中 n 是链表的长度。

您的资料还提到了 C++ 标准模板库 (STL) 中的 list。STL 中的 list 是一个双向链表。它提供了一系列方便的成员函数来操作列表,例如插入 (insert, push_front, push_back)、删除 (erase, pop_front, pop_back, remove, remove_if, clear)、访问元素 (front, back)、排序 (sort)、合并 (merge) 等。STL list 的设计使得在列表中进行插入和删除操作非常高效。

总而言之,列表是一种常用的线性数据结构,它通常通过链表来实现,链表由相互连接的节点组成,每个节点存储数据和指向下一个(或上一个)节点的指针。链表具有动态性和高效的插入删除操作的优点,但在随机访问方面效率较低。C++ STL 提供了方便易用的 list 容器,它是一个双向链表的实现。

好的,根据您提供的资料,特别是第三章第七节“Lists in the Standard Template Library”,以下是以表格方式列出的 std::list 的常用成员函数及其操作,以及一个演示程序。

list 常用成员函数

成员函数 操作 来源
list() 构造一个空列表
list(size_type n, const T& el = T()) 构造一个包含 n 个 el 副本的列表 (如果未提供 el,则使用默认构造函数 T())。
list(iterator first, iterator last) 构造一个包含由迭代器 firstlast 指示范围内的元素的列表
list(const list<T>& lst) 复制构造函数
begin() 返回一个指向列表第一个节点的迭代器
const_begin() const 返回一个指向列表第一个节点的常量迭代器
end() 返回一个指向列表最后一个节点之后位置的迭代器
const_end() const 返回一个指向列表最后一个节点之后位置的常量迭代器
clear() 移除列表中的所有节点
empty() const 如果列表不包含任何节点则返回 true,否则返回 false
erase(iterator i) 移除迭代器 i 所引用的节点,并返回一个引用被移除元素之后元素的迭代器
erase(iterator first, iterator last) 移除由迭代器 firstlast 指示范围内的节点,并返回一个引用被移除的最后一个元素之后元素的迭代器
front() 返回列表中第一个节点的元素
const front() const 返回列表中第一个节点的常量元素
insert(iterator i, const T& el = T()) 在迭代器 i 引用的节点之前插入元素 el,并返回一个引用新插入节点的迭代器
insert(iterator i, size_type n, const T& el) 在迭代器 i 引用的节点之前插入 nel 的副本
insert(iterator i, iterator first, iterator last) 在迭代器 i 引用的节点之前插入由迭代器 firstlast 指示范围内的元素
max_size() const 返回列表中可能包含的最大节点数
merge(list<T>& lst) 对于已排序的当前列表和 lst,移除 lst 中的所有节点并将它们按排序顺序插入到当前列表中
merge(list<T>& lst, Comp f) 对于已排序的当前列表和 lst,移除 lst 中的所有节点,并根据二元布尔函数 f() 指定的排序顺序插入到当前列表中
pop_back() 移除列表的最后一个节点
pop_front() 移除列表的第一个节点
push_back(const T& el) 在列表的末尾插入元素 el
push_front(const T& el) 在列表的开头插入元素 el
remove(const T& el) 从列表中移除所有包含元素 el 的节点
remove_if(Pred f) 移除所有使得一元布尔函数 f() 返回 true 的节点
resize(size_type n, const T& el = T()) 使列表包含 n 个节点,如果当前大小小于 n,则添加 n - size() 个包含元素 el 的节点;如果当前大小大于 n,则丢弃多余的节点
sort() 以升序对列表中的元素进行排序
sort(Comp f) 根据二元布尔函数 f() 指定的顺序对列表中的元素进行排序
splice(iterator i, list<T>& lst) 移除列表 lst 中的所有节点,并将它们插入到当前列表中迭代器 i 所指示的位置之前
splice(iterator i, list<T>& lst, iterator j) 移除列表 lst 中迭代器 j 所引用的节点,并将其插入到当前列表中迭代器 i 所指示的位置之前
splice(iterator i, list<T>& lst, iterator first, iterator last) 移除列表 lst 中由迭代器 firstlast 指示范围内的节点,并将它们插入到当前列表中迭代器 i 所指示的位置之前
swap(list<T>& lst) 将当前列表的内容与另一个列表 lst 的内容进行交换

list 演示程序

以下程序示例了 std::list 的一些常用操作:

#include <iostream>
#include <list>
#include <string>
#include <algorithm> // 需要使用 std::find

using namespace std;

// 用于 remove_if 的谓词
bool isShort(const string& s) {
    return s.length() < 5;
}

// 用于 sort 的比较函数
bool compareLength(const string& s1, const string& s2) {
    return s1.length() < s2.length();
}

int main() {
    // 构造列表
    list<string> my_list1;
    my_list1.push_back("apple");
    my_list1.push_front("banana");
    my_list1.push_back("orange");
    my_list1.push_front("grape");

    cout << "初始列表 my_list1: ";
    for (const string& s : my_list1) {
        cout << s << " ";
    }
    cout << endl;

    // 插入元素
    list<string>::iterator it = find(my_list1.begin(), my_list1.end(), "orange");
    if (it != my_list1.end()) {
        my_list1.insert(it, "kiwi");
    }

    cout << "在 'orange' 前插入 'kiwi' 后的 my_list1: ";
    for (const string& s : my_list1) {
        cout << s << " ";
    }
    cout << endl;

    // 删除元素
    my_list1.pop_front();
    my_list1.remove("apple");

    cout << "移除首元素和 'apple' 后的 my_list1: ";
    for (const string& s : my_list1) {
        cout << s << " ";
    }
    cout << endl;

    // 使用 remove_if
    my_list1.remove_if(isShort);

    cout << "移除长度小于 5 的字符串后的 my_list1: ";
    for (const string& s : my_list1) {
        cout << s << " ";
    }
    cout << endl;

    // 排序
    my_list1.sort(compareLength);

    cout << "按长度排序后的 my_list1: ";
    for (const string& s : my_list1) {
        cout << s << " ";
    }
    cout << endl;

    // 清空列表
    my_list1.clear();
    cout << "清空 my_list1 后,是否为空? " << my_list1.empty() << endl;

    // 构造第二个列表
    list<string> my_list2 = {"zebra", "yak"};

    // 使用 splice
    list<string> my_list3 = {"cat", "dog", "elephant"};
    list<string>::iterator it_splice = next(my_list3.begin()); // 指向 "dog"
    my_list3.splice(it_splice, my_list2);

    cout << "将 my_list2 拼接 (splice) 到 my_list3 的 'dog' 之前: ";
    for (const string& s : my_list3) {
        cout << s << " ";
    }
    cout << endl;

    return 0;
}

程序说明

  1. 我们包含了 <iostream> 用于输入输出,<list> 使用 std::list 容器,<string> 使用字符串,<algorithm> 使用 std::find 查找元素。
  2. 创建了几个 std::list<string> 类型的列表 my_list1my_list2my_list3,并使用 push_backpush_front 添加了一些初始元素。
  3. 演示了如何使用迭代器和 find 函数在列表中查找特定元素,并使用 insert 在找到的元素之前插入新的元素 “kiwi”。
  4. 展示了 pop_front(移除首元素)和 remove(移除指定值的元素)的用法。
  5. 使用了 remove_if 函数,它接受一个谓词函数 isShort,用于移除列表中所有长度小于 5 的字符串。
  6. 使用 sort 函数对列表进行排序,这里我们提供了一个自定义的比较函数 compareLength,按字符串的长度进行排序。
  7. 展示了 clear 函数用于移除列表中的所有元素,以及 empty 函数用于检查列表是否为空。
  8. 创建了 my_list2my_list3,并使用 splice 函数将 my_list2 中的所有元素移动到 my_list3 中指定迭代器位置之前。注意,splice 操作会将源列表中的元素移除。

这个示例程序涵盖了 std::list 中一些最常用的成员函数,帮助您理解它们的基本用法。您可以编译并运行此程序以查看实际效果。