1.splice的几种用法
   
项目开发过程中,发现stl中的list有splice方法,而且splice方法还挺实用,可以很方便地对链表进行一些连接断开的操作。因此我们下面来详细总结并实测一下splice的几种用法。
list1.splice(iterator position, list2)
list1.splice(iterator position, list2, iterator i)
list1.splice(iterator position, list2, iterator first, iterator last)
    splice有以上三种函数签名,其中
    
    list1表示被拼接的列表,操作以后其结构会发生改变(如果有改变的话)
    
    iterator position表示操作开始时list1的迭代器位置
    
    list2为将其元素拼接到list1的列表。
    
    iterator i是list2中要拼接的迭代器元素。
    
    iterator first, iterator last则是list2中要拼接元素的第一个与最后一个。
   
下面我们通过几个实例来进行测试。
    
    
    2.全部拼接
   
void run3() {
    list<int> l1 = { 1, 2, 3 }; 
    list<int> l2 = { 4, 5 }; 
    list<int> l3 = { 6, 7, 8 }; 
  
    // 将l2全部加入l1,插入的位置为l1的开头
    l1.splice(l1.begin(), l2); 
  
    cout << "list l1 after splice operation" << endl; 
    for (auto ele : l1) cout << ele << " "; 
    cout << endl;
    cout << "list l2 after splice operation" << endl; 
    cout << "l2.size is: " << l2.size() << endl;
  
    // 将l1全部加入l3的末尾 
    l3.splice(l3.end(), l1); 
  
    // at the end of l3 
    cout << "list l3 after splice operation" << endl; 
    for (auto ele : l3) cout << ele << " "; 
}
如果我们将上面的代码运行,最终将得到如下输出
list l1 after splice operation
4 5 1 2 3 
list l2 after splice operation
l2.size is: 0
list l3 after splice operation
6 7 8 4 5 1 2 3 
l1.splice(l1.begin(), l2);
    这行代码,表示将l2全部拼接到l1,拼接的位置在l1的头位置。并且注意拼接完成以后,l2此时的size已经变为0。
    
    同理当
   
l3.splice(l3.end(), l1);
这行代码执行以后,会将l1全部拼接到l3,拼接位置在l3的尾部。
    
    
    3.拼接单个元素
   
void run4() {
    list<int> mylist = {1, 2, 3, 4, 5};
    list<int>::iterator needit;
    for(auto it=mylist.begin(); it!=mylist.end(); it++) {
        if (*it==3) needit = it;
    }
    mylist.splice(mylist.begin(), mylist, needit);
    for(int ele: mylist) {
        cout<<ele<<" ";
    }
}
mylist.splice(mylist.begin(), mylist, needit);
重点解释一下上面这行代码。注意此时list2的位置,我们传入的跟list1相同,也即意味着我们操作的是同一个列表。我们想要做的事情是将列表中的某一个元素,移动到列表表头的位置。所以最后代码的输出为:
3 1 2 4 5 
所以,用splice方法就可以达到我们上述的目的。这样的好处在于,简单不易出错,帮我们简化省略了链表中各种指针断链再重新链接的过程。
    
    
    4.移动一段元素
   
上面解释的移动一个元素,如果我们想移动多个连续的一段元素,那么自然也可以采用类似的办法。
void run5() {
    list<int> mylist = {1, 2, 3, 4, 5, 6, 7};
    list<int>::iterator beginit, endit;
    for(auto it=mylist.begin(); it!=mylist.end(); it++) {
        if (*it==3) beginit = it;
        if (*it==5) endit = it;
    }
    mylist.splice(mylist.begin(), mylist, beginit, endit);
    for(int ele: mylist) {
        cout<<ele<<" ";
    }
}
具体原理跟上面类似,不再多做解释。最终代码输出为
3 4 1 2 5 6 7 
从上面的测试代码不难看出,最终的last元素,不包含在移动范围之内。
 
