顺序容器:forward list单链表 详解

目录

前言

一、定义及初始化

[1.定义 forward_list 对象](#1.定义 forward_list 对象)

2.初始化方式

[二、向 forward_list 对象中添加元素](#二、向 forward_list 对象中添加元素)

1.在头部添加元素

2.在指定位置之后添加元素

[三、forward_list 常用迭代器](#三、forward_list 常用迭代器)

[四、forward_list 常用运算符](#四、forward_list 常用运算符)

[五、forward_list 常用成员函数](#五、forward_list 常用成员函数)

[1.empty 成员函数](#1.empty 成员函数)

[2.front 成员函数](#2.front 成员函数)

[3.push_front 成员函数](#3.push_front 成员函数)

[4.pop_front 成员函数](#4.pop_front 成员函数)

[5.insert_after 成员函数](#5.insert_after 成员函数)

[6.erase_after 成员函数](#6.erase_after 成员函数)

[六、forward_list 特有成员函数](#六、forward_list 特有成员函数)

[1.merge 特有成员函数](#1.merge 特有成员函数)

[2.remove 特有成员函数](#2.remove 特有成员函数)

[3.remove_if 特有成员函数](#3.remove_if 特有成员函数)

[4.reverse 特有成员函数](#4.reverse 特有成员函数)

[5.sort 特有成员函数](#5.sort 特有成员函数)

[6.unique 特有成员函数](#6.unique 特有成员函数)

七、综合练习

[练习 1:forward_list 基本操作](#练习 1:forward_list 基本操作)

[练习 2:使用 forward_list 特有成员函数](#练习 2:使用 forward_list 特有成员函数)

[练习 3:使用 forward_list 实现一个简单的队列](#练习 3:使用 forward_list 实现一个简单的队列)


前言

forward_list 是 C++11 引入的标准库容器,定义在 <forward_list> 头文件中,位于 std 命名空间内。它是一种单向链表(单链表) ,只支持从前往后遍历,不支持随机访问,但在链表头部的插入和删除操作非常高效。


一、定义及初始化

使用forward list,必须包含头文件<forward_list>:

cpp 复制代码
#include <forward_list>

1.定义 forward_list 对象

cpp 复制代码
#include <forward_list>

// 定义一个存储 int 类型的 forward_list
std::forward_list<int> flist;

// 定义一个存储 std::string 类型的 forward_list
std::forward_list<std::string> strFlist;

2.初始化方式

  1. 默认初始化:创建一个空 forward_list

    cpp 复制代码
    std::forward_list<int> flist; // 空 forward_list
  2. 列表初始化

    cpp 复制代码
    std::forward_list<int> flist = {1, 2, 3, 4, 5};
    std::forward_list<int> flist2{1, 2, 3, 4, 5}; // 与上面等价
  3. 使用另一个 forward_list 初始化

    cpp 复制代码
    std::forward_list<int> flist1 = {1, 2, 3, 4, 5};
    std::forward_list<int> flist2 = flist1; // 拷贝初始化
    std::forward_list<int> flist3(flist1); // 拷贝构造
  4. 使用迭代器范围初始化

    cpp 复制代码
    std::forward_list<int> flist1 = {1, 2, 3, 4, 5};
    std::forward_list<int> flist2(flist1.begin(), flist1.end()); // 包含 flist1 的所有元素
    
    // 从其他容器初始化
    std::vector<int> vec = {6, 7, 8, 9, 10};
    std::forward_list<int> flist3(vec.begin(), vec.end()); // 包含 vec 的所有元素
  5. 使用填充构造函数

    cpp 复制代码
    // 注意:forward_list 没有接受元素个数和初始值的构造函数
    // 可以使用生成器或循环来填充
    std::forward_list<int> flist;
    for (int i = 0; i < 5; ++i) {
        flist.push_front(10);
    }
    // 此时 flist 包含 {10, 10, 10, 10, 10},但顺序是反的
    // 可以使用 reverse() 来反转
    flist.reverse(); // 现在 flist 包含 {10, 10, 10, 10, 10}

二、向 forward_list 对象中添加元素

forward_list 是单向链表,因此只能在头部或指定位置之后添加元素。

1.在头部添加元素

  1. push_front 成员函数

    • 功能:在 forward_list 头部添加一个元素
    • 参数:要添加的元素值
    • 返回值:无
    cpp 复制代码
    std::forward_list<int> flist = {2, 3, 4};
    flist.push_front(1); // flist 现在包含 {1, 2, 3, 4}
  2. emplace_front 成员函数(C++11)

    • 功能:在 forward_list 头部直接构造一个元素
    • 参数:构造元素所需的参数
    • 返回值:无
    • 优点:避免了额外的拷贝或移动操作,比 push_front 更高效
    cpp 复制代码
    std::forward_list<std::pair<int, std::string>> flist;
    flist.emplace_front(1, "one"); // 直接在头部构造 pair 对象
    flist.push_front({2, "two"}); // 先构造临时 pair 对象,再移动到头部

2.在指定位置之后添加元素

  1. insert_after 成员函数

    • 功能:在指定迭代器位置之后插入元素
    • 参数
      • 版本 1:pos, value - 在迭代器 pos 之后插入 value
      • 版本 2:pos, count, value - 在迭代器 pos 之后插入 count 个 value
      • 版本 3:pos, first, last - 在迭代器 pos 之后插入迭代器范围 [first, last) 中的元素
    • 返回值:指向新插入的第一个元素的迭代器
    cpp 复制代码
    std::forward_list<int> flist = {1, 3, 4, 5};
    
    // 在第一个元素之后插入元素 2
    auto it = flist.begin(); // 指向第一个元素 1
    flist.insert_after(it, 2); // flist 现在包含 {1, 2, 3, 4, 5}
    
    // 在头部之后插入 2 个 0
    it = flist.begin(); // 指向第一个元素 1
    flist.insert_after(it, 2, 0); // flist 现在包含 {1, 0, 0, 2, 3, 4, 5}
    
    // 在指定位置之后插入另一个 forward_list 的元素
    std::forward_list<int> flist2 = {6, 7, 8};
    it = flist.end(); // 注意:forward_list 的 end() 返回的是尾后迭代器,不能用于 insert_after
    // 应该找到最后一个元素
    it = flist.begin();
    while (std::next(it) != flist.end()) {
        ++it;
    }
    flist.insert_after(it, flist2.begin(), flist2.end()); // flist 现在包含 {1, 0, 0, 2, 3, 4, 5, 6, 7, 8}
  2. emplace_after 成员函数(C++11)

    • 功能:在指定迭代器位置之后直接构造一个元素
    • 参数
      • pos - 插入位置之前的迭代器
      • 构造元素所需的参数
    • 返回值:指向新构造元素的迭代器
    • 优点:避免了额外的拷贝或移动操作
    cpp 复制代码
    std::forward_list<std::pair<int, std::string>> flist;
    auto it = flist.before_begin(); // 使用 before_begin() 获取首前迭代器
    flist.emplace_after(it, 1, "one"); // 在头部之后构造 pair 对象

三、forward_list 常用迭代器

forward_list 容器提供了多种迭代器类型,用于遍历容器中的元素。需要注意的是,forward_list 的迭代器是前向迭代器,只支持 ++ 操作,不支持 -- 操作。

  1. 前向迭代器

    • begin():返回指向第一个元素的迭代器
    • end():返回指向最后一个元素之后位置的迭代器
    • before_begin():返回指向第一个元素之前位置的迭代器(首前迭代器)
    • cbefore_begin():返回指向第一个元素之前位置的常量首前迭代器
  2. 常量迭代器

    • cbegin():返回指向第一个元素的常量前向迭代器
    • cend():返回指向最后一个元素之后位置的常量前向迭代器

使用示例:

cpp 复制代码
std::forward_list<int> flist = {1, 2, 3, 4, 5};

// 使用前向迭代器遍历
for (auto it = flist.begin(); it != flist.end(); ++it) {
    std::cout << *it << " "; // 输出: 1 2 3 4 5
}
std::cout << std::endl;

// 使用常量迭代器遍历(不能修改元素)
for (auto it = flist.cbegin(); it != flist.cend(); ++it) {
    std::cout << *it << " "; // 输出: 1 2 3 4 5
    // *it = 10; // 错误:常量迭代器不能修改元素
}
std::cout << std::endl;

// 使用首前迭代器
auto before_first = flist.before_begin();
// 在首前迭代器之后插入元素,相当于在头部插入
flist.insert_after(before_first, 0); // flist 现在包含 {0, 1, 2, 3, 4, 5}

四、forward_list 常用运算符

forward_list 类重载了多种运算符,方便容器操作:

  1. 赋值运算符

    • =:将一个 forward_list 赋值给另一个 forward_list
    cpp 复制代码
    std::forward_list<int> flist1 = {1, 2, 3};
    std::forward_list<int> flist2;
    flist2 = flist1; // flist2 现在包含 {1, 2, 3}
  2. 比较运算符

    • ==:判断两个 forward_list 是否相等
    • !=:判断两个 forward_list 是否不相等
    • <:判断一个 forward_list 是否小于另一个 forward_list(字典序)
    • <=:判断一个 forward_list 是否小于或等于另一个 forward_list
    • >:判断一个 forward_list 是否大于另一个 forward_list
    • >=:判断一个 forward_list 是否大于或等于另一个 forward_list
    cpp 复制代码
    std::forward_list<int> flist1 = {1, 2, 3};
    std::forward_list<int> flist2 = {1, 2, 4};
    bool b1 = (flist1 == flist2); // false
    bool b2 = (flist1 < flist2);  // true(第三个元素 3 < 4)

五、forward_list 常用成员函数

|-------------------------|-------------------|
| forward list l的成员函数 | 含义 |
| l.empty() | 判断是否为空 |
| l.front() | 返回第一个元素的引用 |
| l.push_front() | 头插 |
| l.pop_front() | 头删 |
| l.insert_after() | 插入一个或多个元素,这个效率为常数 |
| l.erase_after() | 删除一个或多个元素 |
| l.swap() | 交换两个list的值 |
| l.clear() | 清空数据 |

1.empty 成员函数

  • 功能:判断 forward_list 是否为空
  • 参数:无
  • 返回值 :如果 forward_list 为空返回 true,否则返回 false
cpp 复制代码
std::forward_list<int> flist1;
std::forward_list<int> flist2 = {1, 2, 3};
std::cout << flist1.empty(); // 输出: 1 (true)
std::cout << flist2.empty(); // 输出: 0 (false)

2.front 成员函数

  • 功能:返回 forward_list 中第一个元素的引用

  • 参数:无

  • 返回值:第一个元素的引用

  • 说明:如果 forward_list 为空,行为未定义

    std::forward_list<int> flist = {1, 2, 3};
    std::cout << flist.front(); // 输出: 1
    flist.front() = 10; // flist 现在包含 {10, 2, 3}

3.push_front 成员函数

  • 功能:在 forward_list 头部添加一个元素

  • 参数:要添加的元素值

  • 返回值:无

    std::forward_list<int> flist = {2, 3, 4};
    flist.push_front(1); // flist 现在包含 {1, 2, 3, 4}

4.pop_front 成员函数

  • 功能:删除 forward_list 头部的一个元素

  • 参数:无

  • 返回值:无

  • 说明:如果 forward_list 为空,行为未定义

    std::forward_list<int> flist = {1, 2, 3, 4};
    flist.pop_front(); // flist 现在包含 {2, 3, 4}
    flist.pop_front(); // flist 现在包含 {3, 4}

5.insert_after 成员函数

  • 功能:在指定迭代器位置之后插入元素

  • 参数

    • 版本 1:pos, value - 在迭代器 pos 之后插入 value
    • 版本 2:pos, count, value - 在迭代器 pos 之后插入 count 个 value
    • 版本 3:pos, first, last - 在迭代器 pos 之后插入迭代器范围 [first, last) 中的元素
  • 返回值:指向新插入的第一个元素的迭代器

    std::forward_list<int> flist = {1, 3, 4, 5};

    // 在第一个元素之后插入元素 2
    auto it = flist.begin(); // 指向第一个元素 1
    flist.insert_after(it, 2); // flist 现在包含 {1, 2, 3, 4, 5}

6.erase_after 成员函数

  • 功能:删除指定迭代器位置之后的元素

  • 参数

    • 版本 1:pos - 删除迭代器 pos 之后的元素
    • 版本 2:first, last - 删除从 first 之后到 last 之前的元素
  • 返回值:指向被删除元素之后位置的迭代器

    std::forward_list<int> flist = {1, 2, 3, 4, 5};

    // 删除第一个元素之后的元素(即第二个元素)
    auto it = flist.begin(); // 指向第一个元素 1
    flist.erase_after(it); // flist 现在包含 {1, 3, 4, 5}

    // 删除从第一个元素之后到第四个元素之前的元素
    it = flist.begin(); // 指向第一个元素 1
    auto end_it = flist.begin();
    std::advance(end_it, 3); // 移动到第四个元素 5 之前的位置
    flist.erase_after(it, end_it); // flist 现在包含 {1, 5}

六、forward_list 特有成员函数

|-------------------------|--------------|
| orward list l特有成员函数 | 含义 |
| l.merge() | 链表合并 |
| l.remove(val) | 删除所有和val相同元素 |
| l.remove_if() | 删除符合条件的元素 |
| l.reverse() | 反转链表中的元素 |
| l.sort() | 排序(默认为升序) |
| l.splice_after() | 链表连结 |
| l.unique() | 删除重复元素 |

1.merge 特有成员函数

  • 功能:合并两个已排序的 forward_list
  • 参数
    • other - 另一个已排序的 forward_list
  • 返回值:无
  • 说明:合并后,other 变为空
cpp 复制代码
std::forward_list<int> flist1 = {1, 3, 5};
std::forward_list<int> flist2 = {2, 4, 6};
flist1.merge(flist2); // flist1 现在包含 {1, 2, 3, 4, 5, 6},flist2 为空

2.remove 特有成员函数

  • 功能:删除所有值等于指定值的元素
  • 参数:要删除的值
  • 返回值:无
cpp 复制代码
std::forward_list<int> flist = {1, 2, 3, 2, 4, 2, 5};
flist.remove(2); // flist 现在包含 {1, 3, 4, 5}

3.remove_if 特有成员函数

  • 功能:删除所有满足指定条件的元素
  • 参数:一个返回 bool 的函数对象或 lambda 表达式
  • 返回值:无
cpp 复制代码
std::forward_list<int> flist = {1, 2, 3, 4, 5, 6};

// 删除所有偶数
flist.remove_if([](int n) { return n % 2 == 0; }); // flist 现在包含 {1, 3, 5}

4.reverse 特有成员函数

  • 功能:反转 forward_list 中元素的顺序
  • 参数:无
  • 返回值:无
cpp 复制代码
std::forward_list<int> flist = {1, 2, 3, 4, 5};
flist.reverse(); // flist 现在包含 {5, 4, 3, 2, 1}

5.sort 特有成员函数

  • 功能:对 forward_list 中的元素进行排序
  • 参数:可选的比较函数
  • 返回值:无
cpp 复制代码
std::forward_list<int> flist = {5, 2, 8, 1, 9};
flist.sort(); // flist 现在包含 {1, 2, 5, 8, 9}

// 使用自定义比较函数(降序)
flist.sort(std::greater<int>()); // flist 现在包含 {9, 8, 5, 2, 1}

6.unique 特有成员函数

  • 功能:删除连续的重复元素,只保留一个
  • 参数:可选的比较函数
  • 返回值:无
cpp 复制代码
std::forward_list<int> flist = {1, 1, 2, 2, 2, 3, 4, 4, 5};
flist.unique(); // flist 现在包含 {1, 2, 3, 4, 5}

七、综合练习

练习 1:forward_list 基本操作

cpp 复制代码
#include <iostream>
#include <forward_list>

int main() {
    // 创建并初始化 forward_list
    std::forward_list<int> flist = {3, 4, 5};
    
    // 在头部添加元素
    flist.push_front(2);
    flist.push_front(1);
    
    // 输出当前 forward_list
    std::cout << "Current forward_list: ";
    for (int x : flist) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    // 访问元素
    std::cout << "Front: " << flist.front() << std::endl;
    
    // 删除头部元素
    flist.pop_front();
    
    // 输出修改后的 forward_list
    std::cout << "After pop_front: ";
    for (int x : flist) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    // 在指定位置之后插入元素
    auto it = flist.begin(); // 指向第一个元素 2
    flist.insert_after(it, 10);
    
    // 输出插入后的 forward_list
    std::cout << "After insert_after: ";
    for (int x : flist) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    // 删除指定位置之后的元素
    it = flist.begin(); // 指向第一个元素 2
    flist.erase_after(it);
    
    // 输出删除后的 forward_list
    std::cout << "After erase_after: ";
    for (int x : flist) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    // 检查 forward_list 状态
    std::cout << "Empty: " << (flist.empty() ? "Yes" : "No") << std::endl;
    
    return 0;
}

练习 2:使用 forward_list 特有成员函数

cpp 复制代码
#include <iostream>
#include <forward_list>

int main() {
    // 创建并初始化 forward_list
    std::forward_list<int> flist = {5, 2, 8, 1, 9, 3, 7, 4, 6};
    
    // 排序
    flist.sort();
    std::cout << "After sort: ";
    for (int x : flist) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    // 反转
    flist.reverse();
    std::cout << "After reverse: ";
    for (int x : flist) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    // 创建另一个 forward_list 并合并
    std::forward_list<int> flist2 = {10, 11, 12};
    flist2.sort(); // 合并前需要排序
    flist.sort();   // 合并前需要排序
    flist.merge(flist2);
    std::cout << "After merge: ";
    for (int x : flist) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    std::cout << "flist2 size: " << std::distance(flist2.begin(), flist2.end()) << std::endl; // 应该为 0
    
    // 添加重复元素并去重
    flist.push_front(5);
    flist.push_front(5);
    flist.push_front(7);
    std::cout << "Before unique: ";
    for (int x : flist) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    flist.sort(); // 去重前最好先排序,确保重复元素连续
    flist.unique();
    std::cout << "After unique: ";
    for (int x : flist) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    // 删除特定元素
    flist.remove(5);
    std::cout << "After remove 5: ";
    for (int x : flist) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    // 删除满足条件的元素
    flist.remove_if([](int n) { return n > 8; });
    std::cout << "After remove_if (>8): ";
    for (int x : flist) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

练习 3:使用 forward_list 实现一个简单的队列

cpp 复制代码
#include <iostream>
#include <forward_list>

class Queue {
private:
    std::forward_list<int> flist;
    // 用于跟踪尾部位置
    std::forward_list<int>::iterator tail;
    
    // 更新尾部迭代器
    void updateTail() {
        if (flist.empty()) {
            tail = flist.before_begin();
        } else {
            tail = flist.begin();
            while (std::next(tail) != flist.end()) {
                ++tail;
            }
        }
    }
public:
    Queue() : tail(flist.before_begin()) {}
    
    // 入队
    void enqueue(int value) {
        if (flist.empty()) {
            flist.push_front(value);
        } else {
            // 如果 tail 无效,更新它
            if (tail == flist.end() || std::next(tail) != flist.end()) {
                updateTail();
            }
            flist.insert_after(tail, value);
            ++tail; // 更新 tail 到新添加的元素
        }
    }
    
    // 出队
    void dequeue() {
        if (!flist.empty()) {
            flist.pop_front();
            updateTail(); // 更新 tail
        }
    }
    
    // 获取队首元素
    int front() {
        if (!flist.empty()) {
            return flist.front();
        }
        return -1; // 表示队列为空
    }
    
    // 检查是否为空
    bool empty() {
        return flist.empty();
    }
    
    // 获取队列大小
    size_t size() {
        return std::distance(flist.begin(), flist.end());
    }
    
    // 打印队列
    void print() {
        std::cout << "Queue: ";
        for (int x : flist) {
            std::cout << x << " ";
        }
        std::cout << std::endl;
    }
};

int main() {
    Queue q;
    
    // 入队
    q.enqueue(1);
    q.enqueue(2);
    q.enqueue(3);
    q.enqueue(4);
    q.enqueue(5);
    
    q.print(); // 输出: Queue: 1 2 3 4 5
    
    // 出队
    q.dequeue();
    q.dequeue();
    
    q.print(); // 输出: Queue: 3 4 5
    
    // 获取队首元素
    std::cout << "Front: " << q.front() << std::endl; // 输出: Front: 3
    
    // 检查队列状态
    std::cout << "Size: " << q.size() << std::endl; // 输出: Size: 3
    std::cout << "Is empty: " << (q.empty() ? "Yes" : "No") << std::endl; // 输出: Is empty: No
    
    return 0;
}
相关推荐
txinyu的博客2 小时前
解析muduo源码之 HttpServer.h & HttpServer.cc
c++
Zzj_tju2 小时前
Java 从入门到精通(九):集合框架入门,List、Set、Map 到底该怎么选?
java·开发语言·list
郝学胜-神的一滴2 小时前
从线程栈到表达式求值:栈结构的核心应用与递归实现
开发语言·数据结构·c++·算法·面试·职场和发展·软件工程
月落归舟2 小时前
排序算法---(二)
数据结构·算法·排序算法
sonnet-10292 小时前
交换排序算法
java·c语言·开发语言·数据结构·笔记·算法·排序算法
2301_788770552 小时前
模拟OJ3
数据结构·算法
charlie1145141912 小时前
通用GUI编程技术——Win32 原生编程实战(十八)——GDI 设备上下文(HDC)完全指南
开发语言·c++·ide·学习·visual studio·win32
sonnet-10292 小时前
堆排序算法
java·c语言·开发语言·数据结构·python·算法·排序算法
tankeven2 小时前
HJ150 全排列
c++·算法