C++ STL: list 的 MergeSort

  • list不能使用STL算法的sort() ——快排,必须使用自己的成员函数sort() 。
  • 因为STL算法sort()只接受RandomAccessIterator。
  • list排序采用了mergesort,时间复杂度是O(nlgn),空间复杂度是O(1)。
template<class T>
struct _list_node{
    typedef void * void_pointer;
    void_pointer prev;
    void_pointer next;
    T data;
};

template<class T>
class 
{
protected:
    _list_node<T> * node;//用一个指针,表示整个环状双向链表
protected:
    //将[first,last)内的所有元素移动到position之前。
    void transfer(iterator position,iterator first,iterator last){
        ... ... 
    }
public:
    void sort();
    void merge(list<T> & x);
};

template<class T>
void list<T>::merge(list<T> & 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;
            transfer(first1,first2,++next);//将[first2,next)的元素移动到first1之前。
            first2 = next;
        }
        else
            ++first1;
    }
    if(first2 != last2) transfer(last1,first2,last2);
}

template<class T>
void list<T>::sort()
{
    //当链表为空或者仅有一个元素,就不进行任何操作
    if(node->next==node || node->next->next ==node)
        return ;
    list<T> carry;
    list<T> counter[64];//用来保存一系列的合并后的有序链表,每一层保存的最大结点数目1,2,4,...
    int fill=0;         //记录了counter数组现在最多使用了几层

    while(!empty() ){ //当链表不为空
        carry.splice(carry.begin(),*this,begin());//将链表的头一个结点截取到carry上。
        int i=0;                                   //i,表示counter的下标
        while(i<fill && !counter[i].empty() ){     
            counter[i].merge(carry);         //将carry合并到counter[i]链表上,carry为空
            carry.swap(counter[i++]);        //交换carry和counter[i],以便和i+1层的合并
        }
        carry.swap(counter[i]); 
        if(i==fill) ++fill;
    }

    for(int i=1;i<fill;++i)                //将所有保存在counter中的有序链表合并到一起
        counter[i].merge(counter[i-1]);
    swap(counter[fill-1];        //将在counter[fill-1]排序好的链表交换给this链表。

}

举例:现有链表其值为{5,9,3,11,1,20},调用list的sort函数;

while(!empty()) 的第一次循环后:

this链表{9,3,11,1,20}
carry{5} ---> empty
counter[0]{5}
counter[1]empty
fill 1

while(!empty()) 的第二次循环后:

this链表{3,11,1,20}
carry{9} ---> {5,9} --->empty
counter[0]empty
counter[1]{5,9}
counter[2]empty
fill 2

while(!empty()) 的第三次循环后:

this链表{11,1,20}
carry{3} --->empty
counter[0]{3}
counter[1]{5,9}
counter[2]empty
fill 2

while(!empty()) 的第四次循环后:

this链表{1,20}
carry 变化过程{11} ---> {3,11}--->{3,5,9,11}--->empty
counter[0]empty
counter[1]empty
counter[2]{3,5,9,11}
fill 3

while(!empty()) 的第五次循环后:

this链表{20}
carry{1} ---> empty
counter[0]{1}
counter[1]empty
counter[2]{3,5,9,11}
fill 3

while(!empty()) 的第六次循环后:

this链表empty
carry{20} ---> {1,20} ---> empty
counter[0]empty
counter[1]{1,20}
counter[2]{3,5,9,11}
fill 3

最后将前0层到fill-1层, counter合并到counter[fill-1].然后交换给this链表。

counter[2]

{1,3,5,9,11,20} ---> empty

this链表{1,3,5,9,11,20}

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值