std::forward_list

std::forward_list

介绍

成员函数

非成员函数

介绍

// forward_list 模板定义
template<class T, class Allocator = std::allocator<T>> class forward_list;	(C++11 起)
namespace pmr {
    template <class T>
    using forward_list = std::forward_list<T, std::pmr::polymorphic_allocator<T>>;
}	(C++17 起)
  • std::forward_list 介绍摘选自 cppreference.com 中文网 std::forward_list 介绍
  • std::forward_list 是支持从容器中的任何位置快速插入和移除元素的容器,不支持快速随机访问
  • 它实现为单链表,且实质上与其在 C 中实现相比无任何开销
  • 与 std::list 相比,此容器在不需要双向迭代时提供更有效地利用空间的存储
  • 在链表内或跨数个链表添加、移除和移动元素,不会非法化当前指代链表中其他元素的迭代器
  • 在从链表移除元素(通过 erase_after )时,指代对应元素的迭代器或引用会被非法化

成员函数

构造析构
#include <QCoreApplication>
#include <algorithm>
#include <forward_list>
#include <iostream>
#include <string>

auto Print(const std::string &msg, const std::forward_list<int> &lst) {
  std::cout << msg << " : ";
  for (auto iter = lst.begin(); iter != lst.end(); ++iter) {
    std::cout << *iter << "\t";
  }
  std::cout << "\n";
}

int main(int argc, char *argv[]) {
  QCoreApplication a(argc, argv);

  using list_int = std::forward_list<int>;
  list_int l1; //默认构造
  Print("l1", l1);

  std::allocator<int> alloc;
  list_int l2(alloc); //设置分配器
  Print("l2", l2);

  list_int l3(5, -1, alloc); //设置元素数量,初始值,分配器
  Print("l3", l3);

  list_int l4(5); //设置元素数量
  Print("l4", l4);

  list_int l5(l3.begin(), l3.end()); //迭代器初始化
  Print("l5", l5);

  list_int l6(l5); //容器拷贝初始化,可设置分配器
  Print("l6", l6);
  list_int l7(l6, alloc);
  Print("l7", l7);

  list_int l8(std::move(l7)); //容器移动构造初始化,可设置分配器
  Print("l8", l8);
  list_int l9(std::move(l8), alloc);
  Print("l9", l9);

  list_int l10{0, 2, 4, 6, 8, 10}; //初始化列表
  Print("l10", l10);
  return 0; // a.exec();
}

输出结果:
l1 :
l2 :
l3 : -1 -1 -1 -1 -1
l4 : 0 0 0 0 0
l5 : -1 -1 -1 -1 -1
l6 : -1 -1 -1 -1 -1
l7 : -1 -1 -1 -1 -1
l8 : -1 -1 -1 -1 -1
l9 : -1 -1 -1 -1 -1
l10 : 0 2 4 6 8 10

元素访问
auto Print(const std::string &msg, const std::forward_list<int> &lst) {
  std::cout << msg << " : ";
  for (auto iter = lst.begin(); iter != lst.end(); ++iter) {
    std::cout << *iter << "\t";
  }
  std::cout << "\n";
}

int main(int argc, char *argv[]) {
  QCoreApplication a(argc, argv);

  using list_int = std::forward_list<int>;
  list_int l1{1, 3, 5, 7, 9}; 
  Print("l1", l1);
  std::cout << "index 0 : " << l1.front() << std::endl; //访问第一个元素
  std::cout << "index 0 : " << l1.front() << std::endl; //访问第一个元素

  return 0; // a.exec();
}

输出结果:
l1 : 1 3 5 7 9
index 0 : 1
index 0 : 1

迭代器
auto Print(const std::string &msg, const std::forward_list<int> &lst) {
  std::cout << msg << " : ";
  for (auto iter = lst.begin(); iter != lst.end(); ++iter) {
    std::cout << *iter << "\t";
  }
  std::cout << "\n";
}

int main(int argc, char *argv[]) {
  QCoreApplication a(argc, argv);

  using list_int = std::forward_list<int>;
  list_int l1{1, 3, 5, 7, 9}; 
  Print("l1", l1);

  //返回指向首元素前一元素的迭代器。此元素表现为占位符,试图访问它会导致未定义行为。仅有的使用情况是在函数
  // insert_after() 、 emplace_after() 、 erase_after() 、 splice_after()
  //和迭代器自增中:自增始前迭代器准确地给出与从 begin()/cbegin()
  //获得者相同的迭代器。
  list_int::iterator biter = l1.before_begin();
  list_int::const_iterator cbiter = l1.cbefore_begin();

  list_int::iterator iter = l1.begin();
  std::cout << "l1 : ";
  for (; iter != l1.end(); ++iter) {
    std::cout << *iter << "\t";
  }
  std::cout << "\n";

  list_int::const_iterator citer = l1.begin();
  std::cout << "l1 : ";
  for (; citer != l1.end(); ++citer) {
    std::cout << *citer << "\t";
  }
  std::cout << "\n";

  return 0; // a.exec();
}

输出结果:
l1 : 1 3 5 7 9
l1 : 1 3 5 7 9
l1 : 1 3 5 7 9

容量
auto Print(const std::string &msg, const std::forward_list<int> &lst) {
  std::cout << msg << " : ";
  for (auto iter = lst.begin(); iter != lst.end(); ++iter) {
    std::cout << *iter << "\t";
  }
  std::cout << "\n";
}

int main(int argc, char *argv[]) {
  QCoreApplication a(argc, argv);

  using list_int = std::forward_list<int>;
  list_int l1{1, 3, 5, 7, 9};
  Print("l1", l1);

  std::cout << std::boolalpha << "test.empty : " << l1.empty()
            << "\n"; // 检查容器是否为空
  std::cout << "test.max_size : " << l1.max_size()
            << "\n"; // 返回可容纳的最大元素数,和平台有关

  return 0; // a.exec();
}

输出结果:
l1 : 1 3 5 7 9
test.empty : false
test.max_size : 1152921504606846975

修改器
auto Print(const std::string &msg, const std::forward_list<int> &lst) {
  std::cout << msg << " : ";
  for (auto iter = lst.begin(); iter != lst.end(); ++iter) {
    std::cout << *iter << "\t";
  }
  std::cout << "\n";
}

int main(int argc, char *argv[]) {
  QCoreApplication a(argc, argv);

  using list_int = std::forward_list<int>;
  list_int l1{1, 3, 5, 7, 9};
  Print("l1", l1);

  l1.clear(); // 清除内容
  Print("l1", l1);

  l1.insert_after(l1.cbefore_begin(), 10); //在某个元素后插入新元素
  Print("l1", l1);

  l1.emplace_after(l1.cbefore_begin(), 20); //在元素后原位构造元素
  Print("l1", l1);
  l1.erase_after(l1.cbegin()); //擦除元素后的元素
  Print("l1", l1);
  l1.push_front(30); //插入元素到容器起始
  Print("l1", l1);
  l1.emplace_front(40); //在容器头部原位构造元素
  Print("l1", l1);
  l1.pop_front(); //移除首元素
  Print("l1", l1);
  l1.resize(10); //改变容器中可存储元素的个数
  Print("l1", l1);

  list_int l2{2, 4, 6, 8, 10};
  Print("l2", l2);
  l1.swap(l2); //交换内容
  Print("l1", l1);
  Print("l2", l2);

  return 0; // a.exec();
}

输出结果:
l1 : 1 3 5 7 9
l1 :
l1 : 10
l1 : 20 10
l1 : 20
l1 : 30 20
l1 : 40 30 20
l1 : 30 20
l1 : 30 20 0 0 0 0 0 0 0 0
l2 : 2 4 6 8 10
l1 : 2 4 6 8 10
l2 : 30 20 0 0 0 0 0 0 0 0

操作
auto Print(const std::string &msg, const std::forward_list<int> &lst) {
  std::cout << msg << " : ";
  for (auto iter = lst.begin(); iter != lst.end(); ++iter) {
    std::cout << *iter << "\t";
  }
  std::cout << "\n";
}

int main(int argc, char *argv[]) {
  QCoreApplication a(argc, argv);

  using list_int = std::forward_list<int>;
  list_int l1{1, 3, 5, 7, 9};
  list_int l2{2, 4, 6, 8, 10};
  Print("l1", l1);
  Print("l2", l2);

  l1.merge(l2); //合并二个已排序列表
  Print("l1", l1);
  Print("l2", l2);

  list_int l3{10, 20, 30};
  l1.splice_after(l1.before_begin(), l3); //从另一 forward_list 移动元素
  Print("l1", l1);

  l1.remove(20); //移除满足特定标准的元素
  Print("l1", l1);
  l1.remove_if([](int v) -> bool { return v > 20; });
  Print("l1", l1);

  l1.reverse(); //将该链表的所有元素的顺序反转
  Print("l1", l1);

  list_int l4{2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 3, 3, 5};
  l4.unique(); //删除连续的重复元素
  Print("l4", l4);

  list_int l5{5, 6, 1, 2, 4};
  l5.sort(); //对元素进行排序
  Print("l5", l5);

  return 0; // a.exec();
}

输出结果:
l1 : 1 3 5 7 9
l2 : 2 4 6 8 10
l1 : 1 2 3 4 5 6 7 8 9 10
l2 :
l1 : 10 20 30 1 2 3 4 5 6 7 8 9 10
l1 : 10 30 1 2 3 4 5 6 7 8 9 10
l1 : 10 1 2 3 4 5 6 7 8 9 10
l1 : 10 9 8 7 6 5 4 3 2 1 10
l4 : 2 3 4 3 5
l5 : 1 2 4 5 6

非成员函数

auto Print(const std::string &msg, const std::forward_list<int> &lst) {
  std::cout << msg << " : ";
  for (auto iter = lst.begin(); iter != lst.end(); ++iter) {
    std::cout << *iter << "\t";
  }
  std::cout << "\n";
}

int main(int argc, char *argv[]) {
  QCoreApplication a(argc, argv);

  using list_int = std::forward_list<int>;
  list_int l1{1, 3, 5, 7, 9};
  list_int l2{2, 4, 6, 8, 10};
  Print("l1", l1);
  Print("l2", l2);

  std::cout.setf(std::ios::boolalpha);
  std::cout << "l1 == l2 : " << (l1 == l2) << std::endl;
  std::cout << "l1 != l2 : " << (l1 != l2) << std::endl;
  std::cout << "l1 > l2 : " << (l1 > l2) << std::endl;
  std::cout << "l1 >= l2 : " << (l1 >= l2) << std::endl;
  std::cout << "l1 < l2 : " << (l1 < l2) << std::endl;
  std::cout << "l1 <= l2 : " << (l1 <= l2) << std::endl;
  std::cout.unsetf(std::ios::boolalpha);
  // c++20 废弃以上操作符重载,提供三路运算符 operator <=> ()

  std::swap(l1, l2);
  Print("l1", l1);
  Print("l2", l2);

  return 0; // a.exec();
}

输出结果:
l1 : 1 3 5 7 9
l2 : 2 4 6 8 10
l1 == l2 : false
l1 != l2 : true
l1 > l2 : false
l1 >= l2 : false
l1 < l2 : true
l1 <= l2 : true
l1 : 2 4 6 8 10
l2 : 1 3 5 7 9

起始

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`std::vector` 和 `std::list` 是两种不同的数据结构,各有自己的特点和适用场景。以下是它们之间的一些主要区别: 1. 存储方式:`std::vector` 是一个动态数组,它使用连续的内存块来存储元素,可以通过索引快速访问元素。而 `std::list` 是一个双向链表,它的元素通过指针链接在一起,不能通过索引直接访问元素,需要遍历链表来访问。 2. 插入和删除操作:由于 `std::vector` 使用连续的内存存储元素,插入和删除元素可能涉及到内存的重新分配和元素的移动,因此在特定位置进行插入和删除操作的成本较高。而 `std::list` 作为链表,在任意位置进行插入和删除操作的成本都是常数时间复杂度,不涉及元素的移动。 3. 访问和查找操作:由于 `std::vector` 使用连续的内存存储元素,可以通过索引直接访问元素,也可以通过指针进行迭代,因此在访问和查找操作上比较高效。而 `std::list` 作为链表,访问和查找操作需要遍历整个链表,时间复杂度较高。 4. 内存分配:由于 `std::vector` 使用连续的内存存储元素,它在内存分配上是连续的,有利于 CPU 缓存的利用。而 `std::list` 的内存分配是离散的,可能导致额外的内存碎片。 根据上述区别,可以根据实际需求选择合适的数据结构。如果需要频繁进行随机访问、插入和删除操作不频繁,并且对内存占用有限制,可以使用 `std::vector`。如果需要频繁进行插入和删除操作、访问和查找操作相对较少,并且不关心内存占用,可以使用 `std::list`。当然,在特定情况下,也可以根据具体需求选择其他数据结构,如 `std::deque` 或 `std::forward_list`。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值