Forward-List的基本内容
此容器始于C++11,其内部实现为一个single linked list(单链表)管理元素。
想要使用此容器,必须首先包含<forward_list>头文件
在这个头文件中forwar list被定义为命名空间std内的一个class template:
namespace std{
template<typename T,typename Allocator = allocator<T>>
class forward_list;
}
T可以被指定为任意元素类型,可有可无的第二个template参数定义处内存模型。默认的内存模型是allocator,由C++标准库提供
Forward-List的能力
以下是C++standard对它的描述:"我们希望forward_list和你自己手写的C-style singly linked list相比较之下没有任何时间或空间上的开销。任何性质如果与这个目标相抵触,我们就放弃该项性质"。
相较于list,forward list有以下约束:
Forward list只提供向前迭代器,而不是双向迭代器。因此它也不支持反向迭代器,这意味着rbegin(),rend(),crbegin(),crend()等成员函数也不提供。
Forward list不提供成员函数size()。这是遵循C++standard目标带来的必然结果。
Forward list没有指向最末元素的锚点(anchor)。因而不提供处理最末元素的成员函数back(),push_back()和pop_back()。
对于所有"令元素被安插或删除于forward list的某特定位置上"的成员函数,forward list都提供特殊版本(这是基于单链表特性所导致的)。基于这个差异,这些成员函数名称都带有_after的后缀。例如insert_after()取代inert()。
基于第四点的原因,forward list提供before_begin()和cbefore_begin(),他们可以用来让"名称带有_after后缀"的算法交换第一元素。
除了这些差异,forward list就像一个list
Forward list不提供随机访问。
在任何位置上安插和移除元素速度都很快。
安插和删除元素不会造成"指向其他元素"的pointer,reference和iterator失效。
Forward list对待异常的态度是,几乎每一个操作要么成功,要么就不起作用。
Forward list提供许多特殊成员函数用于搬移和移除元素。这些成员函数是一般算法的快速版本。
Forward-list 的操作
创建,复制,销毁(Create,Copy,and Destory)
forward list<T>c //Default构造函数,产生于一个空的forward list容器,没有任何元素
forward list<T>c(c2) //Copy构造函数,将c建立为c2的一份拷贝(所有元素都被拷贝)
forward list<T>c=c2 //Copy构造函数,将c建立为c2的一份拷贝(所有元素都被拷贝)
forward list<T>c(rv)//Move构造函数,取rv的内容建立一个新的forward list
forward list<T>c=rv//Move构造函数,取rv的内容建立一个新的forward list
forward list<T>c(n)//生成一个大小为n的forward list,每个元素的值都是elem
forward list<T>c(n,elem)//生成一个大小为n的forward list,每个元素的值都是elem
forward list<T>c(beg,end)//生成一个forward list,以区间[begin,end)作为元素初值
forward list<T>c(initlist)//生成一个forward list,以初始值列表的元素为初值
forward list<T>c =initlist//生成一个forward list,以初始值列表的元素为初值
c.~forward list()//销毁所有元素,释放内存
非更易型操作(Nonmodifying Operation)
与list的区别是,forward list不提供size()。原因是它不存储元素的目前数量,也无法在常量时间内将它算出来。如果你必须计算元素个数,可使用distance()辅助函数。
#include<forward list>
#include<iterator>
std::forward list<int>l;
std::cout<<"l.size()"<<std::distance(l.begin(),l.end())
<<std::endl;
请注意distance()具有线性复杂度
c.empty() //返回是否容器为空(相当于size()==0但也许较快)
c.max_size() //返回元素个数之最大可能量
c1==c2 //返回c1是否等于c2
c1!=c2 //返回c1是否不等于c2
c1>c2 //返回c1是否大于c2
c1<c2 //返回c1是否小于c2
c1>=c2 //返回c1是否大等于c2
c1<=c2 //返回c1是否小等于c2
赋值(Assignment)
c=c2 //将c2的全部元素赋值给c
c=rv //将rv的所有元素都已move assign的方式给予c
c=initlist //将初始值列表的所有元素赋值给c
c.assign(n,elem) //赋值给list,n个元素的值都是elem值
c.assign(beg,end) //将区间[begin,end)的元素赋值给list
c.assign(initlist)//将初始值列表的元素赋值给list
c1.swap(c2) //置换c1和c2的值
swap(c1,c2) //置换c1和c2的值
元素访问(Element Access)
欲访问forward list的所有元素,你必须使用range-based for循环,特定的操作函数或迭代器。和list相比,你唯一能够访问的元素是第一元素。
c.front()//返回第一元素(并不检查是否存在第一元素)
迭代器相关函数(Iterator Function)
由于是向前迭代器,你无法调用reverse迭代器,无法调用需要双向或者随机迭代器的算法,如(sort)。此外还提供了before_begin()和cbefore_begin(),为了能够修改第一元素。
c.begin() //返回一个指向首处 forward iterator
c.cbegin() //返回一个const forward iterator
c.end() //返回一个指向末尾下一个位置的 forward iterator
c.cend() //返回一个指向末尾下一个位置的const forward iterator
c.before_begin()//返回一个指向首处前一个位置的 forward iterator
c.cbefore_begin()//返回一个指向首处前一个位置的const forward iterator
注意:before_begin()和cbefore_begin()并不代表forward list的任意一个有效位置;提领这些位置会导致不明确的行为。
元素的安插和移除元素素(Inserting and Removing)
c.push_front()//附加elem的拷贝于容器的首处
c.pop_front()//移除第一个元素,但是不返回它
c.insert_after(pos,elem)//在pos的后方插入elem的一个拷贝,并且返回新元素的位置
c.insert_after(pos,n,elem)//在pos的后方插入elem的n个拷贝,并且返回第一个新元素的位置
c.insert_after(pos,beg,end)//在pos的后方插入[begin,end)区间的拷贝,并且返回第一个新元素的位置
c.insert_after(pos,initlist)//在pos的后方插入初始化列表的拷贝,并且返回第一个新元素的位置
c.emplace_after(pos,args...)//在pos的后方插入以args作为初值的元素,并且返回新元素的位置
c.emplace_front(args...)//首处插入以args作为初值的元素,并且返回新元素的位置
c.erase_after(pos)//移除pos位置之后的元素,不返回任何元素
c.erase_after(beg,end)//移除[begin,end)区间内的元素,不返回任何元素
c.remove(val)//移除所有值为val的元素
c.remove_if(op)//移除所有造成op(elem)结果为true的元素
c.resize(num)//将元素数量改为num,如果size()变大,则以元素default构造函数完成初始化
c.resize(num,elem)//将元素数量改为num,如果size()变大,则以elem的拷贝作为新元素的值
c.clear()//移除所有元素,将容器清空
当使用这些成员函数,并结合before_begin(),一个典型的forward list元素访问动作如下:
std::forward list<int>fwlist{1,2,3};
fwlist.insert(fwlist.before_begin(),{77,88,99});
注意:调用_after成员函数并传入end或cend()会导致不明确的行为,因为如果要在forward list的尾端附加一个新元素,你不许传入中断元素的位置。
fwlist.insert_after(fwlist.end(),9999);
//RUNTIME ERROR:appending element after end is underfined behavior
下方有一个例子:
#include<forward_list>
using namespace std;
int main(){
forward_list<int>list{1,2,3,4,5,97,98,99};
auto posBefore=list.before_begin();
for(auto pos=list.begin();pos!=list.end();++pos,++posBefore){
if(*pos%2==0)break;
}
list.insert_after(posBefore,42);
for(auto it:list)cout<<it<<" ";
}
程序输出结果为:
1 42 2 3 4 5 97 98 99
Forward-list提供的特殊更易型操作
c.unique() //如果存在若干相邻而数值相同的元素,就移除重复元素,只留一个
c.unique() //如果存在若干相邻都使op()的结果为true的元素,就移除重复元素,只留一个
c.splice_after(pos,c2) //将c2的所有元素转移到c之内,迭代器pos之后
c.splice_after(pos,c2,c2pos) //将c2的c2pos所指元素转移到c内迭代器pos所指位置之后(c和c2可相同)
c.splice_after(pos,c2,c2beg,c2end) //将c2的c2beg和c2end区间(不含头尾)内元素转移到c内迭代器pos之后位置(c和c2可相同)
c.sort() //以元素的operator <为准则对所有元素排序
c.sort(op) //以元素的op()为准则对所有元素排序
c.merge(c2) //假设c和c2容器都包含op()准则下的已排序元素,将c2的全部元素转移到c,并保证合并后的list仍为以排序
c.merge(c2,op) //假设c和c2容器都包含已排序元素,将c2的全部元素转移到c,并保证合并后的list在op()准则下仍为已排序
c.reverse() //将所有元素反序
异常处理(Exception Handing)
forward list对于异常处理的态度和保证,与list完全相同。
Forward List运用实例
#include<forward_list>
#include<iostream>
#include<algorithm>
#include<iteraotor>
#include<string>
using namespace std;
void printLists(const string&s,const forward_list<int>&l1,const forward_list<int>&l2){
cout<<s<<endl;
cout<<" list1: ";
copy(l1.cbegin(),l1.cend(),ostream_iterator<int>(cout," ");
cout<<endl<<" list2: ";
copy(l2.cbegin(),l2.cend(),ostream_iterator<int>(cout," ");
cout<<endl;
}
int main(){
forward_list<int>list1{1,2,3,4};
forward_list<int>list2{77,88,99};
printLists("initial:",list1,list2);
list2.insert_after(list2.before_begin(),99);
list2.push_front(10);
list2.insert_after(list2.before_begin(),{10,11,12,13});
printLists("6 new elems:",list1,list2);
list1.insert_after(list1.before_begin(),list2.begin(),list2.end());
printLists("list2 into list1:",list1,list2);
list2.erase_after(list1.begin());
list2.erase_after(find(list2.begin(),list2.end()),99,list2.end());
printLists("delete 2nd and after 99:",list1,list2);
list1.sort();
list2=list1;
list2.unique();
printLists("sorted and unique:",list1,list2);
list1.merge(list2);
printLists("merged:",list1,list2);
}
执行结果:
initial:
list1: 1 2 3 4
list2: 77 88 99
6 new elems:
list1: 1 2 3 4
list2: 10 11 12 13 10 99 77 88 99
list2 into list1:
list1: 10 11 12 13 10 99 77 88 99 1 2 3 4
list2: 10 11 12 13 10 99 77 88 99
delete 2nd and after 99:
list1: 10 12 13 10 99 77 88 99 1 2 3 4
list2: 10 11 12 13 10 99
sorted and unique:
list1: 1 2 3 4 10 10 12 13 77 88 99 99
list2: 1 2 3 4 10 12 13 77 88 99
merged:
list1: 1 1 2 2 3 3 4 4 10 10 10 12 12 13 13 77 77 88 88 99 99 99
list2: