标准库并未给每个容器添加大量功能,而是提供了一组算法,这些算法中的大多数都独立于任何特定的容器,这些算法是通用的:它们可用于不同类型的容器和不同类型的元素。
大多数算法都定义在头文件algorithm中。标准库还在头文件numeric中定义了一组数值泛型算法。
查找是否存在val,返回的是指向第一个出现val的迭代器,若不存在val,则返回container.end()
find(container.begin(),container.end(),val)
find_if算法可用来查找第一个具有特定大小的元素,接受一对迭代器,表示一个范围。但与find不同的是,find_if的第三个参数是一个谓词。
返回val出现的次数
count(container.begin(),container.end(),val)
一些算法只会读取其输入范围内的元素,而从不改变元素。
对于只读算法,通常最好使用cbegin()和cend(),但如果要使用算法返回的迭代器来改变元素的值,就需要使用begin()和end()作为参数。
只读算法例如,find,count,accumulate
accumulate定义在头文件numeric中,下示代码表示对vec中的元素求和,和的初值是0
int sum = accumulate(vec.begin(),vec.end(),0);
accumulate第三个参数的类型决定了函数中使用哪个加法运算符以及返回值的类型。
string sum = accumulate(vec.begin(),vec.end(),string(""));
用于确定两个序列是否保存相同的值。它将第一个序列中的每个元素与第二个序列中的对应元素进行比较,如果所有元素都对应相等,则返回true,否则返回false。equal可以用来比较两个不同类型的容器中的元素,而且元素类型也不必一样,只要能用==来比较两个元素类型即可。 例如,vec可以是vector
equal(vec.begin(),vec.end(),vec2.begin())
equal基于一个重要的假设:假定第二个序列至少与第一个序列一样长,此算法要处理第一个序列中的每个元素,它假定每个元素在第二个序列中都有一个与之对应的元素。
vector<int>v1{1,3,5,7,9};
vector<int>v2{ 1,3,5,7,9,2,4,6 };
equal(v1.begin(),v1.end(),v2.begin());//true
vector<int>v3{2,1,3,5,7,9,2,4,6 };
equal(v1.begin(),v1.end(),v3.begin());//false
equal(v1.begin(),v1.end(),v3.begin()+1);//true
一些算法将新值赋予序列中的元素。当我们使用这类算法时,必须注意确保序列原大小至少不小于我们要求算法写入的元素数目。算法不会执行容器操作,因此它们自身不可能改变容器的大小。一些算法会自己向输入范围写入元素,这些算法本质上并不危险,它们最多写入与给定序列一样多的元素。
下示代码表示将输入范围中的每一个元素都设置为10
fill(vec.begin(),vec.end(),10)
从vec.begin()开始的n个元素设置为val,其中容器vec的大小至少为n
fill_n(vec.begin(),n,val)
插入迭代器是一种向容器中添加元素的迭代器。
back_inserter定义在头文件Iterator中,接受一个指向容器的引用,返回一个与该容器绑定的插入迭代器。通过此迭代器赋值时,赋值运算符会调用push_back将一个具有给定值的元素添加到容器中。
vector<int>vec{1,3,5,7,9};
auto it = back_inserter(vec);
fill_n(it,10,5);
for (auto a : vec) {
cout << a << " ";
}
cout << endl;
输出结果为:
1 3 5 7 9 5 5 5 5 5 5 5 5 5 5
由于传入的参数是插入迭代器,因此每次赋值都会在vec上调用push_back,最终向vec的末尾添加了10个元素,每个元素的值都是5。
将输入范围中的元素拷贝到v2中,v2至少要包含与输入序列一样多的元素。
copy返回的是拷贝到v2尾元素之后的位置。
auto iter=copy(v1.begin(),v1.end(),v2.begin());
示例代码
vector<int>vec{1,3,5,7,9};
vector<int>vec2{ 1,2,3,4,5,6,7,8,9};
auto it = copy(vec.begin(), vec.end(), vec2.begin());
for (auto a : vec2) {
cout << a << " ";
}
cout << endl;
cout <<*it<< endl;
输出结果:
1 3 5 7 9 6 7 8 9
6
将输入序列中值为0的元素改为42
replace(vec.begin(), vec.end(),0,42);
如果希望保留原序列不变,可以调用 replace_copy
replace_copy(vec.begin(), vec.end(),back_inserter(vec2),0,42);
示例代码一:
vector<int>vec{1,3,5,7,9};
vector<int>vec2;
replace_copy(vec.begin(), vec.end(), back_inserter(vec2), 3, 42);
for (auto a : vec2) {
cout << a << " ";
}
cout << endl;
输出结果:
1 42 5 7 9
示例代码二:
vector<int>vec{1,3,5,7,9};
vector<int>vec2{ 1,2,3,4,5,6,5,8,9};
replace(vec2.begin(), vec2.end(), 5,10);
replace_copy(vec.begin(), vec.end(), back_inserter(vec2), 3, 42);
for (auto a : vec2) {
cout << a << " ";
}
cout << endl;
输出结果:此处插入迭代器调用push_back
1 2 3 4 10 6 10 8 9 1 42 5 7 9
某些算法会重排容器中元素的顺序。
sort是利用元素类型的<运算符来实现排序的。
sort(vec.begin(), vec.end());
sort还可接受第三个参数,此参数是一个谓词,以此来重载sort的默认行为。
要求源容器中,重复元素相邻存放,返回最后一个不重复元素之后的位置
auto end_unique=unique(vec.begin(), vec.end());
示例代码:
vector<int>vec{1,3,5,7,9,3,5,2,7,4};
sort(vec.begin(), vec.end());
cout << "sort后:";
for (auto a : vec) {
cout << a << " ";
}
cout << endl;
auto it = unique(vec.begin(), vec.end());
cout << "unique后:";
for (auto a : vec) {
cout << a << " ";
}
cout << endl;
cout << "unique返回的迭代器指向的元素:" << *it << endl;
vec.erase(it,vec.end());
cout << "erase后:";
for (auto a : vec) {
cout << a << " ";
}
cout << endl;
sort后:1 2 3 3 4 5 5 7 7 9
unique后:1 2 3 4 5 7 9 7 7 9
unique返回的迭代器指向的元素:7
erase后:1 2 3 4 5 7 9
从输出结果可以看出,此例重复元素是3,5,7,unique后:1 2 3 4 5 7 9 7 7 9,而最后三个元素是7 7 9不是3 5 7,此处是由算法决定的。unique只是返回最后一个不重复元素之后的位置。
要求源容器中,重复元素相邻存放
auto end_unique=unique_copy(vec.begin(), vec.end(),vec2.begin());
示例代码:
vector<int>vec{1,3,5,7,9,3,7,2,5};
list<int>lst;
sort(vec.begin(), vec.end());
unique_copy(vec.begin(),vec.end(),back_inserter(lst));
for (auto a : lst) {
cout << a << " ";
}
输出结果:
1 2 3 5 7 9
谓词是一个可调用的表达式,其返回结果是一个能用作条件的值。
一元谓词:只接受单一参数。
二元谓词:有两个参数。
接受谓词参数的算法对输入序列中的元素调用谓词,因此,元素类型必须能转换为谓词的参数类型。
示例:
bool isShorter(const string &s1,const string &s2){
return s1.size()<s2.size();
}
//按长度由短至长排序words
sort(words.begin(),words.end(),isShorter);
稳定排序算法,维持相等元素的原有顺序。
stable_sort(words.begin(),words.end(),isShorter);
对容器内容按谓词进行划分,使得谓词为true的值会排在容器的前半部分, 使得谓词为false的值会排在容器的后半部分。算法返回一个迭代器,指向最后一个使谓词为true的元素之后的位置。
auto it=partition(vec.begin(),vec.end(),谓词);
测试代码:
bool bigThan5(const string & s) {
return s.size() >= 5;
}
void test1013() {
vector<string>vec{"hellol","ha","hou","hello1w", "hi","hellob", "hellocd", };
auto it=partition(vec.begin(),vec.end(),bigThan5);
auto beg = vec.begin();
while (beg!=it) {
cout << *beg << " ";
beg++;
}
cout << endl;
cout << "vec:";
for (auto a : vec) {
cout << a << " ";
}
cout << endl;
}
输出结果:
hellol hellocd hellob hello1w
vec:hellol hellocd hellob hello1w hi hou ha
一个lambda表达式表示一个可调用的代码单元,我们可将其理解为一个未命名的内联函数。与任何函数类似,一个lambda具有一个返回类型、一个参数列表和一个函数体。但与函数不同,lambda可能定义在函数内部,一个lambda表达式具有如下形式:
[捕获列表](参数列表)->返回类型{函数体}
其中,捕获列表是一个lambda所在函数中定义的局部变量的列表(通常为空)。
我们可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体。
示例中定义了一个可调用对象f,它不接受参数,返回42
auto f = [] {return 42;};
lambda的调用方式与普通函数的调用方式相同,都是使用调用运算符:
cout<<f()<<endl;//打印42
如果忽略返回类型,lambda根据函数体中的代码推断出返回类型。如果函数体只是一个return语句,则返回类型从返回的表达式的类型推断而来。如果lambda 的函数体包含任何单一return语句之外的内容,且未指定返回类型,则返回void。
find_if算法对输入序列中的每个元素调用给定的谓词,返回第一个使谓词返回非0值的元素,如果不存在这样的元素,则返回尾后迭代器。
find_if接受一元谓词——我们传递给它的任何函数都必须严格接受一个参数,以便能用来自输入序列中的一个元素调用它。
如果我们想使用find_if算法来查找第一个具有特定大小的元素。则我们需要接受一个string和一个长度。因此,此处可以使用上述介绍的lambda表达式。
auto wc = find_if(words.begin(),words.end(),[sz](const string &a){return a.size()>=sz;});
这里对find_if的调用返回一个迭代器,指向第一个长度不小于给定参数sz的元素,如果这样的元素不存在,则返回words.end()的一个拷贝。
对输入序列中的元素进行打印
for_each(vec.begin(),vec.end(),[](const string &s){cout<<s<<" ";});
此处lambda 的捕获列表为空,但却使用了cout,是因为一个lambda可以直接使用定义在当前函数之外的名字。
捕获列表只用于局部非static变量,lambda可以直接使用局部static变量和在它所在函数之外声明的名字。
类似参数传递,变量的捕获方式也可以是值或引用。
与传值参数类似,采用值捕获的前提是变量可以拷贝。与参数不同,被捕获的变量的值是在lambda创建时拷贝,而不是调用时拷贝:
int a=10;
auto f=[a]{return a;};
a=5;
auto j=f();//j=10
int a=10;
auto f=[&a]{return a;};
a=5;
auto j=f();//j=5
当以引用方式捕获一个变量时,必须保证在lambda执行时变量是存在的。
我们可以从一个函数返回lambda。函数可以直接返回一个可调用对象,或者返回一个类对象,该类含有可调用对象的数据成员。如果函数返回一个lambda,则与函数不能返回一个局部变量的引用类似,此lambda也不能包含引用捕获。
sz为隐式捕获,值捕获方式
auto wc = find_if(words.begin(),words.end(),[=](const string &a){return a.size()>=sz;});
os为隐式捕获,引用捕获方式
for_each(vec.begin(),vec.end(),[&](const string &s){os<<s<<" ";});
混合使用隐式捕获和显式捕获
当混合使用隐式捕获和显式捕获时,显式捕获的变量必须使用与隐式捕获不同的方式。即,如果隐式捕获是引用方式(使用了&),则显式捕获命名变量必须采用值方式,因此不能在其名字前使用&。类似的,如果隐式捕获是值方式(采用了=),则显式捕获命名变量必须采用引用方式,即在名字前使用& 。
示例:c隐式捕获,值捕获方式,os显式捕获,引用捕获方式
for_each(vec.begin(),vec.end(),[=,&os](const string &s){os<<s<<c;});
默认情况下,对于一个值被拷贝的变量,lambda不会改变其值,如果我们希望能改变一个被捕获的变量的值,就必须在参数列表后加上关键字mutable。因此,可变lambda能省略参数列表。
若不加关键字mutable,在下述代码中, ++a会报错。
int a = 10;
auto f = [a]()mutable {return ++a; };
auto j = f();
cout << "a:" << a << endl; //a=10
cout << "j:" << j << endl; //j=11
示例:
void test() {
int num = 5;
auto f = [num]()mutable->bool {if (num == 0)return true; num--; cout <<" f()的num:"<< num <<" "; return false; };
for (int i = 0; i < 6;i++) {
cout << "test中的num:"<<num<<" ";
cout << f() << endl;
}
}
输出结果:
test中的num:5 f()的num:4 0
test中的num:5 f()的num:3 0
test中的num:5 f()的num:2 0
test中的num:5 f()的num:1 0
test中的num:5 f()的num:0 0
test中的num:5 1
当我们需要为一个lambda定义返回类型时,必须使用尾置返回类型。
示例代码:
transform(vi.begin(),vi.end(),vi.begin(),
[](int i)->int
{if(i<0)
return -i;
else
return i;});
接受一对迭代器表示一个输入范围,还接受一个谓词,对输入范围中每个元素执行,count_if返回一个计数值,表示谓词有多少次为真。
如果lambda的捕获列表为空,通常可以用函数来代替它。
bind函数定义在头文件functional中。bind函数可看做一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。
调用bind 的一般形式:
auto newCallable=bind(callable,arg_list)
其中,newCallable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数,即,当我们调用newCallable时,newCallable会调用callable,并传递给它arg_list中的参数。
arg_list中的参数可能包含形如_n的名字,其中n是一个整数。这些参数是“占位符”,表示newCallable的参数,它们占据了传递给newCallable的参数的“位置”。数值n表示生成的可调用对象中参数的位置:_1为newCallable的第一个参数,_2为newCallable的第二个参数,以此类推。
示例代码:
auto check6=bind(check_size,_1,6);
string s="hello";
check6(s);//会调用 check_size(s,6);
将原来基于lambda 的find_if版本:
auto wc = find_if(words.begin(),words.end(),[sz](const string &a){return a.size()>=sz;});
替换为如下bind版本:
auto wc = find_if(words.begin(),words.end(),bind(check_size,_1,sz));
当find_if对words中的string调用这个对象时,这些对象会调用check_size,将给定的string和sz传递给它。因此,find_if可以有效地对输入序列中每个string调用check_size,实现string的大小与sz的比较。
名字_n都定义在一个名为placeholders的命名空间中,而这个命名空间本身定义在std命名空间中,例如,_1对应的using声明为:
using std::placeholders::_1
由placeholders定义的所有名字都可用的声明:
using namespace std::placeholders
与bind函数一样,placeholders命名空间也定义在functional头文件中。
auto g=bind(f,a,b,_2,c,_1);
调用g(x,y)会调用f(a,b,y,c,x)
按单词长度由短至长排序
sort(words.begin(),words.end(),isShorter);
按单词长度由长至短排序
sort(words.begin(),words.end(),bind(isShorter,_2,_1));
在第一个调用中,当sort需要比较两个元素A和B时,它会调用isShorter(A,B)。在第二个对sort的调用中,传递给isShorter的参数被交换,因此比较两个元素时,就好像调用isShorter(B,A)一样。
默认情况下,bind的那些不是占位符的参数被拷贝到bind返回的可调用对象中,但是有时对有些绑定的参数我们希望以引用方式传递,或是要绑定参数的类型无法拷贝,我们就必须使用标准库ref函数:
错误用法:for_each(words.begin(),words.end(),bind(print,os,_1,' '));
正确用法:for_each(words.begin(),words.end(),bind(print,ref(os),_1,' '));
函数ref返回一个对象,包含给定的引用,此对象是可以拷贝的,标准库中还有一个cref函数,生成一个保存const引用的类。与bind一样,函数ref和cref也定义在头文件functional中。
插入器是一种迭代器适配器,它接受一个容器,生成一个迭代器,能实现向给定容器添加元素。当我们通过一个插入迭代器进行赋值时,该迭代器调用容器操作来向给定容器的指定位置插入一个元素。
list<int>lst = { 1,2,3,4 };
auto it = back_inserter(lst);
for (int i = 5; i < 10;i++) {
*it = i;
}
for (auto a:lst) {
cout << a << " ";
}
输出结果:
1 2 3 4 5 6 7 8 9
调用push_back
list<int>lst = { 1,2,3,4 };
auto it = front_inserter(lst);
for (int i = 5; i < 10;i++) {
*it = i;
}
for (auto a:lst) {
cout << a << " ";
}
输出结果:
9 8 7 6 5 1 2 3 4
调用push_front
list<int>lst = { 1,2,3,4 };
auto it = inserter(lst,lst.begin());
for (int i = 5; i < 10;i++) {
*it = i;
}
for (auto a:lst) {
cout << a << " ";
}
输出结果
5 6 7 8 9 1 2 3 4
示例代码中,
*it = i;相当于 it=lst.insert(it,i);++it;
即一直是在原来元素的位置之前加入新的元素。
虽然iostream类型不是容器,但标准库定义了可以用于这些IO类型对象的迭代器。istream_iterator读取输入流,ostream_iterator向一个输出流写数据。这些迭代器将它们对应的流当做一个特定类型的元素序列来处理。通过使用流迭代器,我们可以用泛型算法从流对象读取数据以及向其写入数据。
当创建一个流迭代器时,必须指定迭代器将要读写的对象类型。一个istream_iterator使用>>来读取流。因此,istream_iterator要读取的类型必须定义了输入运算符。
当创建一个istream_iterator时,我们可以将它绑定到一个流:
istream_iterator
我们还可以默认初始化迭代器,这样就创建了一个可以当作尾后值使用的迭代器:
istream_iterator
下面是一个用istream_iterator从标准输入读取数据,存入一个vector的例子:
istream_iterator<int>in_iter(cin);//从cin读取int
istream_iterator<int>int_eof; //尾后迭代器
while(in_iter!=int_eof)
vec.push_back(*in_iter++);
该程序可重写为如下形式:
istream_iterator<int>in_iter(cin);//从cin读取int
istream_iterator<int>int_eof; //尾后迭代器
vector<int>vec(in_iter,int_eof);//从迭代器范围构造vec
我们可以用一对表示元素范围的迭代器来构造vec。这两个迭代器是istream_iterator,这意味着元素范围是通过从关联的流中读取数据获得的。这个构造函数从cin中读取数据,直至遇到文件尾或者遇到一个不是int的数据为止。从流中读取的数据被用来构造vec。
由于算法使用迭代器操作来处理数据,而流迭代器又至少支持某些迭代器操作,因此我们至少可以用某些算法来操作流迭代器。
示例,我们可以用一对istream_iterator来调用accumulate:
istream_iterator<int>in(cin), eof;
cout << accumulate(in, eof, 0) << endl;
若输入为1 3 5 7 9
则输出为25,此调用会计算出从标准输入读取的值的和。
我们可以对任何具有输出运算符(<<运算符)的类型定义ostream_iterator。当创建一个ostream_iterator时,我们可以提供(可选的)第二参数,它是一个字符串,在输出每个元素后都会打印此字符串。此字符串必须是一个C风格字符串(即,一个字符串常量或者一个指向以空字符结尾的字符数组的指针)。必须将ostream_iterator绑定到一个指定的流,不允许空的或表示尾后位置的ostream_iterator。
示例代码:
ostream_iterator<int>out_iter(cout," ");
vector<int>vec{1,3,5,7,9};
for (auto a:vec) {
*out_iter++ = a;
}
cout << endl;
输出:
1 3 5 7 9
此处* 和++实际上对ostream_iterator对象不做任何事情,可以写作out_iter = a;
但仍然推荐*out_iter++ = a;
这种写法, 因为这种写法,流迭代器的使用与其他迭代器的使用保持一致。
可以通过调用copy来打印vec中的元素,这比编写循环更简单:
ostream_iterator<int>out_iter(cout," ");
vector<int>vec{1,3,5,7,9};
copy(vec.begin(),vec.end(),out_iter);
cout<<endl;
输出:
1 3 5 7 9
我们可以为任何定义了输入运算符>>的类型创建istream_iterator对象,类似的,只要类型有输出运算符<<,我们就可以为其定义ostream_iterator。
ifstream in("test.txt");
istream_iterator<string>in_iter(in),eof;
ostream_iterator<string>out_iter(cout," ");
vector<string>vec(in_iter,eof);
copy(vec.begin(), vec.end(), out_iter);
cout << endl;
void test1033(string &s1, string &s2, string &s3) {
ifstream in(s1);
ofstream ofs1(s2);
ofstream ofs2(s3);
istream_iterator<int>in_iter(in), eof;
ostream_iterator<int>out1(ofs1, " ");
ostream_iterator<int>out2(ofs2, " ");
while (in_iter!=eof) {
if (*in_iter % 2 == 1) {
*out1++ = *in_iter;
}
else {
*out2++ = *in_iter;
}
in_iter++;
}
}
反向迭代器就是在容器中从尾元素向首元素反向移动的迭代器。对于反向迭代器,递增(以及递减)操作的含义会颠倒过来。递增一个反向迭代器会移动到前一个元素,递减会移动到下一个元素。除了forward_list之外,其他容器都支持反向迭代器。通过调用rbegin、rend、crbegin、crend成员函数来获得反向迭代器。
我们只能从既支持++也支持–的迭代器来定义反向迭代器,因为反向迭代器的目的是在序列中反向移动。
示例代码:
vector<int>vec = {1,3,5,7,2,4,6,8};
for (auto it = vec.crbegin(); it != vec.crend();++it) {
cout << *it << " ";
}
输出结果:
8 6 4 2 7 5 3 1
通过向sort传递一对反向迭代器来将vector整理为递减序:
vector<int>vec = {1,3,5,7,2,4,6,8};
sort(vec.begin(),vec.end());
for (auto a : vec) {
cout << a << " ";
}
cout << endl;
sort(vec.rbegin(), vec.rend());
for (auto a : vec) {
cout << a << " ";
}
输出结果:
1 2 3 4 5 6 7 8
8 7 6 5 4 3 2 1
调用base成员函数即可
反向迭代器的目的是表示元素范围,而这些范围是不对称的,这导致一个重要的结果:当我们从一个普通迭代器初始化一个反向迭代器,或是给一个反向迭代器赋值时,结果迭代器与原来迭代器指向的并不是相同的元素。示例代码如下:
string s = "hello,world,last";
auto it = s.rbegin();
it++; //此时it指向last中的s
*it = 'A';
cout << s << endl;//输出结果为hello,world,laAt
string s = "hello,world,last";
auto it = s.rbegin();
it++;
auto it2 = it.base();//此时it2指向last中的t
*it2 = 'A';
cout << s << endl;//输出结果为hello,world,lasA
例如,查找某以逗号分隔的string中的最后一个单词的示例代码如下:
string s = "hello,world,last";
auto it1 = find(s.begin(),s.end(),',');
cout << "第一个单词:"<<string(s.begin(),it1) <<endl;
auto it2 = find(s.rbegin(), s.rend(), ',');
cout << "最后一个单词错误的方式:" << string(s.rbegin(), it2) << endl;
cout << "最后一个单词正确的方式:" << string(it2.base(),s.end()) << endl;
输出结果:
第一个单词:hello
最后一个单词错误的方式:tsal
最后一个单词正确的方式:last
dest参数是一个表示算法可以写入的目的位置的迭代器,算法假定:按其需要写入数据,不管写入多少个元素都是安全的。
如果dest是一个直接指向容器的迭代器,那么算法将输出数据写到容器中已存在的元素内,更常见的情况,dest被绑定到一个插入迭代器或是一个ostream_iterator。
示例代码如下:
reverse(beg,end) 反转输入范围中元素的顺序
reverse_copy(beg,end,dest) 将元素按逆序拷贝到dest
remove_if(vec.begin(),vec.end(),[](int i){return i%2;})
reverse_copy_if(vec.begin(),vec.end(),back_inserter(vec2),[](int i){return i%2;})
lst和lst2必须是有序的,经merge后,lst2为空,lst为1 2 3 4 5 6 7 8 9 10
list<int>lst{1,3,5,7,10};
list<int>lst2{ 2,4,6,8,9 };
lst.merge(lst2);
list中重复元素相邻,调用unique()即可删除同一个值的连续拷贝,如下代码,调用unique()后lst为1 2 3 4
list<int>lst{1,2,2,3,3,3,4};
lst.unique();
list<int>lst{1,3,5,7,10 };
list<int>lst2{ 2,4,6,8,9 };
lst.splice(lst.begin(),lst2);//lst=2 4 6 8 9 1 3 5 7 10
list<int>lst{1,3,5,7,10 };
list<int>lst2{ 2,4,6,8,9 };
lst.splice(lst.begin(),lst2,lst2.begin());//lst=2 1 3 5 7 10
list<int>lst{1,3,5,7,10 };
list<int>lst2{ 2,4,6,8,9 };
lst.splice(lst.begin(),lst2,lst2.begin(), lst2.end());//lst=2 4 6 8 9 1 3 5 7 10
forward_list<int>flst{1,3,5,7,10 };
forward_list<int>flst2{ 2,4,6,8,9 };
flst.splice_after(flst.begin(),flst2);//flst=1 2 4 6 8 9 3 5 7 10
以下代码,it指向元素6,将6之后的元素8移动到flst中:
forward_list<int>flst{1,3,5,7,10 };
forward_list<int>flst2{ 2,4,6,8,9 };
auto it=flst2.begin();
it++;
it++;
flst.splice_after(flst.begin(),flst2, it);
//flst: 1 8 3 5 7 10
//flst2: 2 4 6 9
forward_list<int>flst{1,3,5,7,10 };
forward_list<int>flst2{ 2,4,6,8,9 };
flst.splice_after(flst.begin(),flst2, flst2.begin(), flst2.end());//flst: 1 4 6 8 9 3 5 7 10 flst2: 2