一篇搞懂C++ STL 单向链表std::forward_list


前言

C++标准模板库(STL)提供了多种容器类来处理不同的数据结构,其中std::forward_list是用于实现单向链表(Singly Linked List)的容器。与其他容器如std::liststd::vector相比,std::forward_list更为轻量,专为需要快速插入和删除操作、以及内存效率的应用场景而设计。本篇文章将详细介绍std::forward_list的特性、与std::list的区别、所有构造函数和操作函数,并通过示例代码帮助你全面理解这一容器的使用方法。


什么是std::forward_list

std::forward_list 是C++11引入的单向链表容器。它的设计非常简单,仅包含指向下一个节点的指针,因此与双向链表(std::list)相比,它占用的内存更少。由于其单向链表的性质,std::forward_list 只能高效地在头部进行插入和删除操作,遍历时只能从头到尾单向访问。

std::forward_liststd::list的区别

std::list是双向链表容器,具有指向前后两个节点的指针,因此可以在头部和尾部进行高效的插入和删除操作,并且支持双向遍历。而std::forward_list则仅有一个指向下一个节点的指针,无法进行反向遍历,也无法在尾部高效地插入或删除。

通过一个简单的字符串图可以更清晰地理解这两者的区别:

// std::forward_list(单向链表)
head
 v
+---+    +---+    +---+
| 1 | -> | 2 | -> | 3 |
+---+    +---+    +---+

// std::list(双向链表)
head                 tail
 v                    ^
+---+    +---+    +---+
| 1 | <->| 2 | <->| 3 |
+---+    +---+    +---+

如图所示,std::forward_list 只能从头到尾进行单向遍历,而std::list 可以在任意方向上遍历,并且更灵活,但代价是更高的内存开销。

std::forward_list的构造函数

  1. 默认构造函数
    创建一个空的forward_list容器。

    std::forward_list<int> flist;
    
  2. 指定大小的构造函数
    创建一个包含n个默认初始化元素的forward_list

    std::forward_list<int> flist(5);  // 创建一个包含5个默认值为0的元素的forward_list
    
  3. 指定大小和初始值的构造函数
    创建一个包含n个元素,每个元素的值为val

    std::forward_list<int> flist(5, 10);  // 创建一个包含5个值为10的元素的forward_list
    
  4. 区间构造函数
    创建一个forward_list,初始化为迭代器范围[first, last)内的元素。

    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::forward_list<int> flist(vec.begin(), vec.end());  // 用vector的元素初始化forward_list
    
  5. 复制构造函数
    创建一个forward_list,它是另一个forward_list的副本。

    std::forward_list<int> flist1 = {1, 2, 3, 4, 5};
    std::forward_list<int> flist2(flist1);  // 复制flist1
    
  6. 移动构造函数
    创建一个forward_list,通过移动另一个forward_list的内容来初始化。

    std::forward_list<int> flist1 = {1, 2, 3, 4, 5};
    std::forward_list<int> flist2(std::move(flist1));  // 移动flist1到flist2
    

std::forward_list的操作函数

  1. push_front()
    在链表头部插入元素。

    std::forward_list<int> flist = {2, 3, 4};
    flist.push_front(1);  // flist = {1, 2, 3, 4}
    
  2. pop_front()
    删除链表头部的元素。

    std::forward_list<int> flist = {1, 2, 3, 4};
    flist.pop_front();  // flist = {2, 3, 4}
    
  3. insert_after()
    在指定位置之后插入元素或元素序列。

    std::forward_list<int> flist = {1, 3, 4};
    auto it = flist.insert_after(flist.begin(), 2);  // 在1之后插入2,flist = {1, 2, 3, 4}
    
  4. erase_after()
    删除指定位置之后的元素。

    std::forward_list<int> flist = {1, 2, 3, 4};
    flist.erase_after(flist.begin());  // 删除2,flist = {1, 3, 4}
    
  5. front()
    返回链表头部的元素。

    std::forward_list<int> flist = {1, 2, 3, 4};
    int frontElem = flist.front();  // frontElem = 1
    
  6. clear()
    清空链表中的所有元素。

    std::forward_list<int> flist = {1, 2, 3, 4};
    flist.clear();  // flist = {}
    
  7. empty()
    判断链表是否为空。

    std::forward_list<int> flist;
    bool isEmpty = flist.empty();  // isEmpty = true
    
  8. size()
    由于std::forward_list的单向链表特性,它没有直接提供size()函数来获取元素个数。通常你需要手动遍历链表来计算元素的数量:

    std::forward_list<int> flist = {1, 2, 3, 4};
    size_t size = std::distance(flist.begin(), flist.end());  // size = 4
    

示例代码

#include <iostream>
#include <forward_list>
#include <iterator>

int main() {
    // 创建一个单向链表
    std::forward_list<int> flist = {3, 4, 5};

    // 在链表头部插入元素
    flist.push_front(2);  // flist = {2, 3, 4, 5}
    flist.push_front(1);  // flist = {1, 2, 3, 4, 5}

    // 插入元素到指定位置后
    auto it = flist.insert_after(flist.begin(), 6);  // flist = {1, 6, 2, 3, 4, 5}

    // 删除指定位置后的元素
    flist.erase_after(flist.begin());  // flist = {1, 2, 3, 4, 5}

    // 删除头部元素
    flist.pop_front();  // flist = {2, 3, 4, 5}

    // 获取链表头部的元素
    std::cout << "Front element: " << flist.front() << std::endl;  // Front element: 2

    // 遍历链表并输出每个元素
    std::cout << "Elements in forward_list: ";
    for (int n : flist) {
        std::cout << n << " ";
    }
    std::cout << std::endl;

    // 计算链表中的元素个数
    size_t size = std::distance(flist.begin(), flist.end());
    std::cout << "Size of forward_list: " << size << std::endl;  // Size of forward_list: 4

    // 清空链表
    flist.clear();
    std::cout << "Size after clearing: " << std::distance(flist.begin(), flist.end()) << std::endl;  // Size after clearing: 0

    return 0;
}

总结

std::forward_list 是一个轻量级的单向链表容器,适用于内存开销敏感的场景,以及需要高效进行

头部插入和删除的场景。尽管它在功能上不如std::list全面,但它的简单性使得它在特定应用中更具优势。通过理解std::forward_list的构造函数和操作函数,并结合实际需求,你可以选择合适的容器来优化程序的性能和内存使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

人才程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值