list源码4(参考STL源码--侯捷):transfer、splice、merge、reverse、sort

list源码1(参考STL源码--侯捷):list节点、迭代器、数据结构

list源码2(参考STL源码--侯捷):constructor、push_back、insert

list源码3(参考STL源码--侯捷):push_front、push_back、erase、pop_front、pop_back、clear、remove、unique

list源码4(参考STL源码--侯捷):transfer、splice、merge、reverse、sort

transfer

list内部提供一个所谓的迁移技术:transfer,将某连续范围的元素迁移到某个指定的位置之前:

//将[first,last]内所有元素移动到position之前
void transfer(iterator position,iterator first,iterator last){
    if(position!=last){
        (*(link_type((*last.node).prev))).next=position.node; //1
        (*(link_type((*first.node).prev))).next=last.node; //2
        (*(link_type((*position.node).prev))).next=first.node; //3
        link_type temp=link_type((*position.node).prev); //4
        (*position.node).prev=(*last.node).prev; //5
        (*last.node).prev=(*first.node).prev; //6
        (*first.node).prev=temp; //7
    }
}

transfer所接受的[first,last]区间,可以存在同一个list里面,上述transfer并非公开接口,list的公开接口是splice;splice:将某个连续范围的元素从一个list移到另一个list的某个定点,使用如下:

#include<bits/stdc++.h>
using namespace std;

int main() {
    list<int> l1={0,1,2,3,4,5};
    int a[4]={11,12,13,14};
    list<int> l2={a,a+4};

    list<int>::iterator it=find(l1.begin(),l1.end(),3);
    list<int>::iterator first=l2.begin();
    list<int>::iterator last=l2.end();
    if(*it==3){
//        l1.splice(it,l2);
        l1.splice(it,l2,first,last);
    }

    for(auto i:l1) cout<<i<<‘ ‘;//0 1 2 11 12 13 14 3 4 5
    cout<<endl;

    l1.reverse();
    for(auto i:l1) cout<<i<<‘ ‘;//5 4 3 14 13 12 11 2 1 0
    cout<<endl;

    l1.sort();
    for(auto i:l1) cout<<i<<‘ ‘;//0 1 2 3 4 5 11 12 13 14
    cout<<endl;
    return 0;
}

splice

public:
    //将x接合于position之前
    void splice(iterator position,list& x){
        if(!x.empty()){
            transfer(position,x.begin(),x.end());
        }
    }
    //将i所指元素接合于position所指位置之前,position和i可指向同一list
    void splice(iterator position, list&, iterator i){
        iterator j=i;
        ++j;
        if(position==i||position==j) return;
        transfer(position,i,j);
    }
    //将[first,last]内的所有元素接合于position所指位置之前
    //position和[first,last]可指向同一个list
    //position不能位于[first,last]之内
    void splice(iterator position, list&, iterator first,iterator last){
        if(last!=first){
            transfer(position,first,last);
        }
    }

merge

//merge()将x合并到*this身上,两个list的内容都必须经过递增排序
template<class T,class Alloc>
void list<T,Alloc>::merge(list<T,Alloc>& x){
    iterator first1=begin();
    iterator last1=end();
    iterator first2=x.begin();
    iterator last2=x.end();

    //注意:前提是两个链表都经过递增排序
    while(first1!=last1&&first2!=last2){
        if(*first2<*first1){
            iterator next=first2;
            tranfer(first1,first2,++next);
            first2=next;
        }
        else
            ++first1;
        if(first2!=last2)
            transfer(last1,first2,last2);
    }
}

 reverse

//reverse()内容逆置
template<class T,class Alloc>
void list<T,Alloc>::reverse(){
    //以下判断:如果空链表或者仅有一个元素,就不进行任何操作
    //使用size()==0||size()==1来判断,虽然也可以,但是比较慢
    if(node->next==node||link_type(node->next)->next==node)
        return;
    iterator first=begin();
    ++first;
    while(first!=end()){
        iterator old=first;
        ++first;
        transfer(begin(),old,first);
    }
}

sort

//list不能使用STL算法sort(),必须使用自己的成员函数sort()
//本函数采用quicksort(看代码好像不是快排,而是归并)
template<class T,class Alloc>
void list<T,Alloc>::sort(){
    //以下判断:如果空链表或者仅有一个元素,就不进行任何操作
    //使用size()==0||size()==1来判断,虽然也可以,但是比较慢
    if(node->next==node||link_type(node->next)->next==node)
        return;
    //新的list作为辅助数据存放区
    list<T,Alloc> carry;
    list<T,Alloc> counter[64];
    int fill=0;
    while(!empty()){
        carray.splice(carry.begin(),*this,begin());
        int i=0;
        while(i<fill&&!counter[i].empty()){
            counter[i].merge(carray);
            carray.swap(counter[i++]);
        }
        carray.swap(counter[i]);
        if(i==fill)
            ++fill;
    }
    for(int i=1;i<fill;++i){
        counter[i].merge(counter[i-1]);
    }
    swap(counter[fill-1]);
}

下面来解释一下sort的实现,以21,45,1,30,52,3,58,47,22,59,0,58为例:

1、counter[0]:21      注:counter[i]存放2i+1个数,当达到第2i+1个数时,移动数据到counter[i+1]中

2、counter[0]:21,45  注:counter[0]元素已满

counter0]:NULL

counter[1]:21,45

3、counter[0]:1

   counter[1]:21,45

4、counter[0]:1,30  注:counter[0]元素已满,利用merge合并counter[0]至counter[1]

   counter[1]:21,45

counter[0]:NULL

counter[1]:1,30,21,45  注:counter[1]元素已满,

counter[0]:NULL

counter[1]:NULL

counter[2]:1,30,21,45

......

最后得到:

   counter[0]:58

counter[1]:0,59

counter[2]:NULL

   counter[3]:1,3,21,30,47,45,52,58

再次归并得到最后结果。

参考地址:https://blog.csdn.net/shoulinjun/article/details/19501811

原文地址:https://www.cnblogs.com/ybf-yyj/p/9903321.html

时间: 2024-11-11 12:23:52

list源码4(参考STL源码--侯捷):transfer、splice、merge、reverse、sort的相关文章

vector源码2(参考STL源码--侯捷)

vector源码1(参考STL源码--侯捷) vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 vector的构造和内存管理 vector所采用的数据结构非常简单:线性连续空间,它是由两个迭代器start和finish分别指向配置得来的连续空间中目前已被使用的范围,并以迭代器end_of_storage指向整块连续空间(含备用空间)的尾端: class vector //详细源码可见 { .......... protected: typedef simple_allo

vector源码1(参考STL源码--侯捷)

vector源码2(参考STL源码--侯捷) vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 vector概述 Vector是动态空间,随着元素的加入,它的内部机制会自行扩充空间纳入新元素,vector的使用效率,关键在于其对大小的控制以及重新配置时的元素迁移效率. Vector定义摘要 template <class T,class Alloc=alloc>//alloc是SGI STL的空间配置器 class vector { public: typedef T

list源码1(参考STL源码--侯捷):list节点、迭代器、数据结构

list概述 list相对于vector复杂得多,list是一个双链表,对于插入元素.删除元素,list都相对比较简单 list节点 template <class T> struct __list_node{ typedef void* void_pointer; void_pointer prev; //类型为void*,其实也可以设置为__list_node<T>* void_pointer next; T data; }; list迭代器 list迭代器必须有能力指向lis

list源码2(参考STL源码--侯捷):constructor、push_back、insert

list的push_back.insert的使用如下: #include<bits/stdc++.h> using namespace std; int main() { int i; list<int> l; cout<<l.size()<<endl; //0 l.push_back(1); l.push_back(3); l.push_back(5); l.push_back(7); l.push_back(9); cout<<l.size(

vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效

vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷) #include<bits/stdc++.h> using namespace std; int main(){ vector<int> v(3,3); vector<int>::iterator it=v.begin(); cout<<v.size()<<" "<<v.capacity()<<endl;//3

重温《STL源码剖析》笔记 第四章

源码之前,了无秘密  ——侯杰 第四章:序列式容器 C++语言本身提供了一个序列式容器array array:分配静态空间,一旦配置了就不能改变. vector: 分配动态空间.维护一个连续线性空间,迭代器类型为:Random Access Iterators 空间配置 typedef simple_alloc<value_type, Alloc> data_allocator 所谓动态增加空间大小,并不是在原空间之后接续新空间,而是以原大小的两倍另外配置一块较大 的空间,然后将原内容拷贝过来

《STL源码剖析》---stl_iterator.h阅读笔记

STL设计的中心思想是将容器(container)和算法(algorithm)分开,迭代器是容器(container)和算法(algorithm)之间的桥梁. 迭代器可以如下定义:提供一种方法,能够依序寻访某个容器内的所有元素,而又无需暴露该容器的内部表达方式. 在阅读代码之前,要先了解一个新概念:Traits编程技法 template <class T> struct MyIter { typedef T value_type //内嵌型别声明 T *ptr; MyIter(T *p = 0

STL&quot;源码&quot;剖析-重点知识总结

STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合套用: 容器(Containers):各种数据结构,如:vector.list.deque.set.map.用来存放数据.从实现的角度来看,STL容器是一种class template. 算法(algorithms):各种常用算法,如:sort.search.copy.erase.从实现的角度来看,STL算法

C++ 《STL源码剖析》学习-vector

本文章是笔者学习<STL源码剖析>的学习笔记,记录的是笔者的个人理解,因为个人的水平有限,难免会有理解不当的地方,而且该书出版的时间比较久,难免会有些不一样.如有不当,欢迎指出. vector是c++中经常用到的数据结构,而且在面试时也会有提及,因此了解vector很重要. 一说到vector,我们就很容易想到另外一个与它十分相似的数据结构,关于它们之间显著的差别,我觉得是在于空间运用的灵活性上.数组是静态的,在声明的时候就要指明其具体的空间大小,而vector是动态的,随着元素的增加,它内部