std::forward_list是在C++11中引入的单向链表或叫正向列表。forward_list具有插入、删除表项速度快、消耗内存空间少的特点,但只能向前遍历。与其它序列容器(array、vector、deque)相比,forward_list在容器内任意位置的成员的插入、提取(extracting)、移动、删除操作的速度更快,因此被广泛用于排序算法。forward_list是一个允许在序列中任何一处位置以常量耗时插入或删除元素的顺序容器(sequence container)。forward_list可以看作是对C语言风格的单链表的封装,仅提供有限的接口,和C中它的实现相比,基本上不会有任何开销。当不需要双向迭代的时候,与std::list相比,该容器具有更高的空间利用率。

forward_list的主要缺点是不能在常量时间内随机访问任意成员,对成员的访问需要线性时间代价;以及存储链接信息需要消耗内存,特别是当包含大量的小规模成员时。forward_list处于效率考虑,有意不提供size()成员函数。获取forward_list所包含的成员个数需要用std::distance(_begin, _end)算法。forward_list中的每个元素保存了定位前一个元素及后一个元素的信息,不能进行直接随机访问操作。

Forward lists are sequence containers that allow constant time insert and erase operations anywhere within the sequence. Forward lists are implemented as singly-linked lists; Singly linked lists can store each of the elements they contain indifferent and unrelated storage locations. The ordering is kept by the association to each element of a link to the next element in the sequence.

Compared to other base standard sequence containers (array, vector and deque), forward_list perform generally better in inserting, extracting and moving elements in any position within the container, and therefore also in algorithms that make intensive use of these, like sorting algorithms.

The main drawback of forward_lists and lists compared to these other sequence containers is that they lack direct access to the elements by their position;For example, to access the sixth element in a forward_list one has to iterate from the beginning to that position, which takes linear time in the distance between these. They also consume some extra memory to keep the linking information associated to each element (which may be an important factor for large lists of small-sized elements).

一个容器就是一些特定类型对象的集合。顺序容器(sequential container)为程序员提供了控制元素存储和访问顺序的能力。这种顺序不依赖于元素的值,而是与元素加入容器时的位置相对应。

标准库中的顺序容器包括:

(1)、vector:可变大小数组。支持快速随机访问。在尾部之外的位置插入或删除元素可能很慢。

(2)、deque:双端队列。支持快速随机访问。在头尾位置插入/删除速度很快。

(3)、list:双向链表。只支持双向顺序访问。在list中任何位置进行插入/删除操作速度都很快。

(4)、forward_list:单向链表。只支持单向顺序访问。在链表任何位置进行插入/删除操作速度都很快。

(5)、array:固定大小数组。支持快速随机访问。不能添加或删除元素。

(6)、string:与vector相似的容器,但专门用于保存字符。随机访问快。在尾部插入/删除速度快。

除了固定大小的array外,其它容器都提供高效、灵活的内存管理。我们可以添加和删除元素,扩张和收缩容器的大小。容器保存元素的策略对容器操作的效率有着固定的,有时是重大的影响。在某些情况下,存储策略还会影响特定容器是否支持特定操作。

例如,string和vector将元素保存在连续的内存空间中。由于元素是连续存储的,由元素的下标来计算其地址是非常快速的。但是,在这两种容器的中间位置添加或删除元素就会非常耗时:在一次插入或删除操作后,需要移动插入/删除位置之后的所有元素,来保持连续存储。而且,添加一个元素有时可能还需要分配额外的存储空间。在这种情况下,每个元素都必须移动到新的存储空间中。

list和forward_list两个容器的设计目的是令容器任何位置的添加和删除操作都很快速。作为代价,这两个容器不支持元素的随机访问:为了访问一个元素,我们只能遍历整个容器。而且,与vector、deque和array相比,这两个容器的额外内存开销也很大。

deque是一个更为复杂的数据结构。与string和vector类似,deque支持快速的随机访问。与string和vector一样,在deque的中间位置添加或删除元素的代价(可能)很高。但是,在deque的两端添加或删除元素都是很快的,与list或forward_list添加删除元素的速度相当。

forward_list和array是新C++标准增加的类型。与内置数组相比,array是一个种更安全、更容易使用的数组类型。与内置数组类似,array对象的大小是固定的。因此,array不支持添加和删除元素以及改变容器大小的操作。forward_list的设计目标是达到与最好的手写的单向链表数据结构相当的性能。因此,forward_list没有size操作,因为保存或计算其大小就会比手写链表多出额外的开销。对其他容器而言,size保证是一个快速的常量时间的操作。

通常,使用vector是最好的选择,除法你有很好的理由选择其他容器。

以下是一些选择容器的基本原则:

(1)、除法你有很好的理由选择其他容器,否则应该使用vector;

(2)、如果你的程序有很多小的元素,且空间的额外开销很重要,则不要使用list或forward_list;

(3)、如果程序要求随机访问元素,应使用vector或deque;

(4)、如果程序要求在容器的中间插入或删除元素,应使用list或forward_list;

(5)、如果程序需要在头尾位置插入或删除元素,但不会在中间位置进行插入或删除操作,则使用deque;

(6)、如果程序只有在读取输入时才需要在容器中间位置插入元素,随后需要随机访问元素,则:首先,确定是否真的需要在容器中间位置添加元素。当处理输入数据时,通常可以很容器地向vector追加数据,然后再调用标准库的sort函数来重排容器中的元素,从而避免在中间位置添加元素。如果必须在中间位置插入元素,考虑在输入阶段使用list,一旦输入完成,将list中的内容拷贝到一个vector中。

如果你不确定应该使用哪种容器,那么可以在程序中只使用vector和list公共的操作:使用迭代器,不使用下标操作,避免随机访问。这样,在必要时选择使用vector或list都很方便。

一般来说,每个容器都定义在一个头文件中,文件名与类型名相同。即,deque定义在头文件deque中,list定义在头文件list中,以此类推。容器均定义为模板类。

顺序容器几乎可以保存任意类型的元素。特别是,我们可以定义一个容器,其元素的类型是另一个容器。这种容器的定义与任何其他容器类型完全一样:在尖括号中指定元素类型(此种情况下,是另一种容器类型)。

除了顺序容器外,标准库还定义了三个顺序容器适配器:stack、queue和priority_queue。适配器(adaptor)是标准库中的一个通用概念。容器、迭代器和函数都有适配器。本质上,一个适配器是一种机制,能使某种事物的行为看起来像另外一种事物一样。一个容器适配器接受一种已有的容器类型,使其行为看起来像一种不的类型。

下面是从其他文章中copy的std::forward_list测试代码,详细内容介绍可以参考对应的reference:

#include "forward_list.hpp"
#include <iostream>
#include <forward_list>
#include <array>
#include <functional>
#include <cmath>///
// reference: http://www.cplusplus.com/reference/forward_list/forward_list/
template<class Container>
static Container by_two(const Container& x)
{Container temp(x);for (auto& x : temp) x *= 2;return temp;
}// a predicate implemented as a function:
static bool single_digit(const int& value) { return (value<10); }// a predicate implemented as a class:
class is_odd_class
{
public:bool operator() (const int& value) { return (value % 2) == 1; }
} is_odd_object;// a binary predicate implemented as a function:
static bool same_integral_part(double first, double second)
{return (int(first) == int(second));
}// a binary predicate implemented as a class:
class is_near_class
{
public:bool operator() (double first, double second){return (fabs(first - second)<5.0);}
} is_near_object;int test_forward_list_1()
{
{ // forward_list::forward_list: Constructs a forward_list container object,// initializing its contents depending on the constructor version usedstd::forward_list<int> first;                      // default: emptystd::forward_list<int> second(3, 77);              // fill: 3 seventy-sevensstd::forward_list<int> third(second.begin(), second.end()); // range initializationstd::forward_list<int> fourth(third);            // copy constructorstd::forward_list<int> fifth(std::move(fourth));  // move ctor. (fourth wasted)std::forward_list<int> sixth = { 3, 52, 25, 90 };    // initializer_list constructorstd::cout << "first:"; for (int& x : first)  std::cout << " " << x; std::cout << '\n';std::cout << "second:"; for (int& x : second) std::cout << " " << x; std::cout << '\n';std::cout << "third:";  for (int& x : third)  std::cout << " " << x; std::cout << '\n';std::cout << "fourth:"; for (int& x : fourth) std::cout << " " << x; std::cout << '\n';std::cout << "fifth:";  for (int& x : fifth)  std::cout << " " << x; std::cout << '\n';std::cout << "sixth:";  for (int& x : sixth)  std::cout << " " << x; std::cout << '\n';
}{ // forward_list::assign: Assigns new contents to the forward_list container,// replacing its current contents, and modifying its size accordinglystd::forward_list<int> first;std::forward_list<int> second;first.assign(4, 15);                           // 15 15 15 15second.assign(first.begin(), first.end());     // 15 15 15 15first.assign({ 77, 2, 16 });                  // 77 2 16std::cout << "first contains: ";for (int& x : first) std::cout << ' ' << x;std::cout << '\n';std::cout << "second contains: ";for (int& x : second) std::cout << ' ' << x;std::cout << '\n';
}{ // forward_list::before_begin: Returns an iterator pointing to the position before the first element in the container.// forward_list::cbefore_begin: Returns a const_iterator pointing to the position before the first element in the container.std::forward_list<int> mylist = { 20, 30, 40, 50 };mylist.insert_after(mylist.before_begin(), 11);mylist.insert_after(mylist.cbefore_begin(), 19);std::cout << "mylist contains:";for (int& x : mylist) std::cout << ' ' << x;std::cout << '\n';
}{ // forward_list::begin: Returns an iterator pointing to the first element in the forward_list container.// forward_list::cbegin: Returns a const_iterator pointing to the first element in the container.// forward_list::end: Returns an iterator referring to the past-the-end element in the forward_list container// forward_list::cend: Returns a const_iterator pointing to the past-the-end element in the forward_list containerstd::forward_list<int> mylist = { 34, 77, 16, 2 };std::cout << "mylist contains:";for (auto it = mylist.begin(); it != mylist.end(); ++it)std::cout << ' ' << *it;for (auto it = mylist.cbegin(); it != mylist.cend(); ++it)std::cout << ' ' << *it;   // cannot modify *itstd::cout << '\n';
}{ // forward_list::clear: Removes all elements from the forward_list container (which are destroyed),// and leaving the container with a size of 0std::forward_list<int> mylist = { 10, 20, 30 };std::cout << "mylist contains:";for (int& x : mylist) std::cout << ' ' << x;std::cout << '\n';mylist.clear();mylist.insert_after(mylist.before_begin(), { 100, 200 });std::cout << "mylist contains:";for (int& x : mylist) std::cout << ' ' << x;std::cout << '\n';
}{ // forward_list::emplace_after: The container is extended by inserting a new element after the element at position.// This new element is constructed in place using args as the arguments for its construction.// forward_list::emplace_front: Inserts a new element at the beginning of the forward_list, right before its current first element.// This new element is constructed in place using args as the arguments for its construction.std::forward_list< std::pair<int, char> > mylist;auto it = mylist.before_begin();it = mylist.emplace_after(it, 100, 'x');it = mylist.emplace_after(it, 200, 'y');it = mylist.emplace_after(it, 300, 'z');std::cout << "mylist contains:";for (auto& x : mylist)std::cout << " (" << x.first << "," << x.second << ")";std::cout << std::endl;mylist.emplace_front(10, 'a');mylist.emplace_front(20, 'b');mylist.emplace_front(30, 'c');std::cout << "mylist contains:";for (auto& x : mylist)std::cout << " (" << x.first << "," << x.second << ")";std::cout << '\n';
}{ // forward_list::empty: Returns a bool value indicating whether the forward_list container is empty, i.e. whether its size is 0std::forward_list<int> first;std::forward_list<int> second = { 20, 40, 80 };std::cout << "first " << (first.empty() ? "is empty" : "is not empty") << std::endl;std::cout << "second " << (second.empty() ? "is empty" : "is not empty") << std::endl;
}{ // forward_list::erase_after: Removes from the forward_list container either a single element (the one after position) or a range of elements std::forward_list<int> mylist = { 10, 20, 30, 40, 50 };// 10 20 30 40 50auto it = mylist.begin();                 // ^it = mylist.erase_after(it);              // 10 30 40 50//    ^it = mylist.erase_after(it, mylist.end()); // 10 30//       ^std::cout << "mylist contains:";for (int& x : mylist) std::cout << ' ' << x;std::cout << '\n';
}{ // forward_list::front: Returns a reference to the first element in the forward_list container.std::forward_list<int> mylist = { 2, 16, 77 };mylist.front() = 11;std::cout << "mylist now contains:";for (int& x : mylist) std::cout << ' ' << x;std::cout << '\n';
}{ // forward_list::insert_after: The container is extended by inserting new elements after the element at positionstd::array<int, 3> myarray = { 11, 22, 33 };std::forward_list<int> mylist;std::forward_list<int>::iterator it;it = mylist.insert_after(mylist.before_begin(), 10);          // 10//  ^  <- itit = mylist.insert_after(it, 2, 20);                          // 10 20 20//        ^it = mylist.insert_after(it, myarray.begin(), myarray.end()); // 10 20 20 11 22 33//                 ^it = mylist.begin();                                             //  ^it = mylist.insert_after(it, { 1, 2, 3 });                        // 10 1 2 3 20 20 11 22 33//        ^std::cout << "mylist contains:";for (int& x : mylist) std::cout << ' ' << x;std::cout << '\n';
}{ // forward_list::max_size: Returns the maximum number of elements that the forward_list container can holdstd::forward_list<int> mylist = { 2, 16, 77 };std::cout << "mylist max size:" << mylist.max_size() << std::endl;
}{ // forward_list::merge: Merges x into the forward_list by transferring all of its elements at their respective ordered positions// into the container (both containers shall already be ordered)// forward_list::sort: Sorts the elements in the forward_list, altering their position within the containerstd::forward_list<double> first = { 4.2, 2.9, 3.1 };std::forward_list<double> second = { 1.4, 7.7, 3.1 };std::forward_list<double> third = { 6.2, 3.7, 7.1 };first.sort();second.sort();first.merge(second);std::cout << "first contains:";for (double& x : first) std::cout << " " << x;std::cout << std::endl;first.sort(std::greater<double>());third.sort(std::greater<double>());first.merge(third, std::greater<double>());std::cout << "first contains:";for (double& x : first) std::cout << " " << x;std::cout << std::endl;
}{ // forward_list::operator=: Assigns new contents to the container, replacing its current contentsstd::forward_list<int> first(4);      // 4 intsstd::forward_list<int> second(3, 5);   // 3 ints with value 5first = second;                        // copy assignmentsecond = by_two(first);                // move assignmentstd::cout << "first: ";for (int& x : first) std::cout << ' ' << x;std::cout << '\n';std::cout << "second: ";for (int& x : second) std::cout << ' ' << x;std::cout << '\n';
}{ // forward_list::pop_front: Removes the first element in the forward_list container, effectively reducing its size by one.std::forward_list<int> mylist = { 10, 20, 30, 40 };std::cout << "Popping out the elements in mylist:";while (!mylist.empty()) {std::cout << ' ' << mylist.front();mylist.pop_front();}std::cout << '\n';
}{ // forward_list::push_front: Inserts a new element at the beginning of the forward_list, right before its current first element.// The content of val is copied (or moved) to the inserted elementusing namespace std;forward_list<int> mylist = { 77, 2, 16 };mylist.push_front(19);mylist.push_front(34);std::cout << "mylist contains:";for (int& x : mylist) std::cout << ' ' << x;std::cout << '\n';
}{ // forward_list::remove: Removes from the container all the elements that compare equal to val.// This calls the destructor of these objects and reduces the container size by the number of elements removedstd::forward_list<int> mylist = { 10, 20, 30, 40, 30, 20, 10 };mylist.remove(20);std::cout << "mylist contains:";for (int& x : mylist) std::cout << ' ' << x;std::cout << '\n';
}{ // forward_list::remove_if: Removes from the container all the elements for which Predicate pred returns true.// This calls the destructor of these objects and reduces the container size by the number of elements removed.std::forward_list<int> mylist = { 7, 80, 7, 15, 85, 52, 6 };mylist.remove_if(single_digit);      // 80 15 85 52mylist.remove_if(is_odd_object);     // 80 52std::cout << "mylist contains:";for (int& x : mylist) std::cout << ' ' << x;std::cout << '\n';
}{ // forward_list::resize: Resizes the container to contain n elementsstd::forward_list<int> mylist = { 10, 20, 30, 40, 50 };// 10 20 30 40 50mylist.resize(3);             // 10 20 30mylist.resize(5, 100);        // 10 20 30 100 100std::cout << "mylist contains:";for (int& x : mylist) std::cout << ' ' << x;std::cout << '\n';
}{ // forward_list::reverse: Reverses the order of the elements in the forward_list container.std::forward_list<int> mylist = { 10, 20, 30, 40 };mylist.reverse();std::cout << "mylist contains:";for (int& x : mylist) std::cout << ' ' << x;std::cout << '\n';
}{ // forward_list::splice_after: Transfers elements from fwdlst into the container inserting them after the element pointed by position.std::forward_list<int> first = { 1, 2, 3 };std::forward_list<int> second = { 10, 20, 30 };auto it = first.begin();  // points to the 1first.splice_after(first.before_begin(), second);// first: 10 20 30 1 2 3// second: (empty)// "it" still points to the 1 (now first's 4th element)second.splice_after(second.before_begin(), first, first.begin(), it);// first: 10 1 2 3// second: 20 30first.splice_after(first.before_begin(), second, second.begin());// first: 30 10 1 2 3// second: 20// * notice that what is moved is AFTER the iteratorstd::cout << "first contains:";for (int& x : first) std::cout << " " << x;std::cout << std::endl;std::cout << "second contains:";for (int& x : second) std::cout << " " << x;std::cout << std::endl;
}{ // forward_list::swap: Exchanges the content of the container by the content of fwdlst,// which is another forward_list object of the same type. Sizes may differstd::forward_list<int> first = { 10, 20, 30 };std::forward_list<int> second = { 100, 200 };std::forward_list<int>::iterator it;first.swap(second);std::swap(first, second);std::cout << "first contains:";for (int& x : first) std::cout << ' ' << x;std::cout << '\n';std::cout << "second contains:";for (int& x : second) std::cout << ' ' << x;std::cout << '\n';
}{ // forward_list::unique: Remove duplicate valuesstd::forward_list<double> mylist = { 15.2, 73.0, 3.14, 15.85, 69.5,73.0, 3.99, 15.2, 69.2, 18.5 };mylist.sort();                       //   3.14,  3.99, 15.2, 15.2, 15.85//  18.5,  69.2,  69.5, 73.0, 73.0mylist.unique();                     //   3.14,  3.99, 15.2, 15.85//  18.5,  69.2,  69.5, 73.0mylist.unique(same_integral_part);  //  3.14, 15.2, 18.5,  69.2, 73.0mylist.unique(is_near_object);      //  3.14, 15.2, 69.2std::cout << "mylist contains:";for (double& x : mylist) std::cout << ' ' << x;std::cout << '\n';
}{ // Performs the appropriate comparison operation between the forward_list containers lhs and rhs.std::forward_list<int> a = { 10, 20, 30 };std::forward_list<int> b = { 10, 20, 30 };std::forward_list<int> c = { 30, 20, 10 };if (a == b) std::cout << "a and b are equal\n";if (b != c) std::cout << "b and c are not equal\n";if (b<c) std::cout << "b is less than c\n";if (c>b) std::cout << "c is greater than b\n";if (a <= b) std::cout << "a is less than or equal to b\n";if (a >= b) std::cout << "a is greater than or equal to b\n";
}{ // get forward_list elements sizestd::forward_list<int> a = { 10, 20, 30 };size_t size = std::distance(a.begin(), a.end());std::cout << "a size: " << size << std::endl;
}return 0;
}

GitHub: https://github.com/fengbingchun/Messy_Test

C++11中std::forward_list单向链表的使用相关推荐

  1. C++/C++11中std::string用法汇总

    C++/C++11中std::string是个模板类,它是一个标准库.使用string类型必须首先包含<string>头文件.作为标准库的一部分,string定义在命名空间std中. st ...

  2. C++/C++11中std::list双向链表的使用

    std::list是双向链表,是一个允许在序列中任何一处位置以常量耗时插入或删除元素且可以双向迭代的顺序容器.std::list中的每个元素保存了定位前一个元素及后一个元素的信息,允许在任何一处位置以 ...

  3. C++/C++11中std::stack的使用

    栈stack 是一个容器适配器(container adaptor)类型,被特别设计用来运行于LIFO(Last-in First-out,后进先出)场景,在该场景中,只能从容器末尾添加和删除元素,其 ...

  4. C++/C++11中std::deque的使用

    std::deque是双端队列,可以高效的在头尾两端插入和删除元素,在std::deque两端插入和删除并不会使其它元素的指针或引用失效.在接口上和std::vector相似.与sdk::vector ...

  5. C++11中std::async的使用

    C++11中的std::async是个模板函数.std::async异步调用函数,在某个时候以Args作为参数(可变长参数)调用Fn,无需等待Fn执行完成就可返回,返回结果是个std::future对 ...

  6. C++11中std::packaged_task的使用

    C++11中的std::packaged_task是个模板类.std::packaged_task包装任何可调用目标(函数.lambda表达式.bind表达式.函数对象)以便它可以被异步调用.它的返回 ...

  7. C++11中std::shared_future的使用

    C++11中的std::shared_future是个模板类.与std::future类似,std::shared_future提供了一种访问异步操作结果的机制:不同于std::future,std: ...

  8. C++11中std::future的使用

    C++11中的std::future是一个模板类.std::future提供了一种用于访问异步操作结果的机制.std::future所引用的共享状态不能与任何其它异步返回的对象共享(与std::sha ...

  9. 概率论中指数分布介绍及C++11中std::exponential_distribution的使用

    指数分布:在深度学习中,我们经常会需要一个在x=0点处取得边界点(sharp point)的分布.为了实现这一目的,我们可以使用指数分布(exponential distribution): p(x; ...

最新文章

  1. 机器学习(实战)facebook地址预测
  2. 2022 AAAI Fellow放榜!SAIL首席科学家颜水成、港科大教授冯雁等10人入选
  3. Gartner:解开关于人工智能的六个迷思
  4. 正则表达式教程手册、正则一点通(Chinar出品)
  5. Android关于SQLiteOpenHelper的封装
  6. 16-01-25---Servlet复习笔记(01)
  7. java的concurrent包
  8. 自定义SpringBoot Starter实现
  9. ZooKeeper自定义数据日志目录
  10. ANN:DNN结构演进History—LSTM_NN
  11. ES6-7 - 箭头函数的实质、箭头函数的使用场景
  12. android 最新写法,详解Android 硬布局item的高级写法
  13. Filecoin Gas基础费率大幅回升至2.78 nanoFIL
  14. pragma autonomous_transaction详解
  15. 中国土壤全磷含量空间分布数据
  16. 短视频app源码开发,Java使用ffmpeg实现音视频分离
  17. LiveReload for mac 软件下载
  18. 记一次优化天猫商城系统高并发的经验
  19. linux生成checksum,SF2281修改Lic授权ID生成新checksum生成器
  20. 深圳海伊视讯布控球成功对接海康萤石云平台安装调式

热门文章

  1. 洛谷P2397 yyy loves Maths VI (mode) 摩尔投票
  2. 数字图像处理——第九章 形态学图像处理
  3. opencv c++ 寻找矩形框_基于Python的OpenCV人脸检测!OpenCV太强了!
  4. 在Ubuntu 14.04 64bit上为Sublime text 3安装搜狗拼音输入法
  5. TCMalloc(Thread-Caching malloc) 基本设计原理
  6. 如何用 ndctl/ipmctl 管理工具 配置不同访问模式的pmem设备
  7. React+Reflux博客实践
  8. 项目/程序的流程走向
  9. c++ stack 的使用
  10. C#利用lambda在函数中创建内部函数