STL源码剖析学习十六:算法之其他算法

replace把区间内所有old_value替换成new_value

replace(first, last, old_value, new_value)
{
    for(; first!=last; ++first)
    {
        if(*first == old_value)
            *first = new_value;
    }
}

replace_if提供一个仿函数判断两个元素是否相等

 

replace_copy把替换后的内容复制到目的容器中

replace_copy(first, last, result, old_value, new_value)
{
    for(; first!=last; ++first,++result)
    {
        *result = *first == *old_value? new_value: *first;
        //要习惯使用三元运算符
    }
    return result;
}

replace_copy_if提供仿函数以判断是否相等

 

 

reverse将容器中的元素颠倒重排
迭代器的特性会影响效率,所以设计成双层架构

reverse(first, last)
{
    __reverse(first, last, iterator_catogory(first));
}
__reverse(first, last, bidirectional_iterator_tag)
{
    while(1)
    {
        if(first == last || first == --last)//注意前缀的--
            return;
        else
            iter_swap(first++, last);
    }
}
__reverse(first, last, random_access_iterator_tag)
{
    while(first<last)//只有随机访问迭代器才可以做这样的判断
    {
        iter_swap(first++, --last);
    }
}

 

reverse_copy(first, last, result)
{
    while(first!=last)
    {
        --last;
        *result = *last;
        ++result;
    }
    return result;
}

 

 

rotate将[first, middle)和[middle, last)的内容互换,和swap_ranges相似,但是后者只能交换两个相同大小的容器
迭代器的能力影响了算法的效率,设计成双层架构

void rotate(first, middle, last)
{
    if(first == middle || middle == last)
        return;
    __rotate(first, middle, last, distance_type(first), iterator_category(first));
}

根据不同的迭代器重载了三个旋转操作
前向迭代器

__rotate(first, middle, last, Distance*, forward_iterator_tag)
{
    for(ForwardIterator i = middle; ;)
    {
        iter_swap(first, i);
        ++first;
        ++i;
        //交换后判断前后两个迭代器是不是已经到头
        if(first == middle)
        {
            //前后同时到(前后等长)
            if(i == last)
                return;
            //前面到了后面没到(前短后长)
            else
                middle = i;
        }
        //前面没到后面到了(前长后短)
        else if(i == last)
        {
            i == middle;
        }
    }
}


双向迭代器

__rotate(first, middle, last, Distance*, bidirectional_iterator_tag)
{
    //前半部分翻转后半部分翻转整体翻转
    reverse(first, middle);
    reverse(middle, last);
    reverse(first, last);
}

 


随机访问迭代器

__rotate(first, middle, last, Distance*, random_access_iterator_tag)
{
    Distance n = __gcd(last-first, middle-first);
    while(n--)
    {
        __rotate_cycle(first, last, first+n, middle-first, value_type(first));
    }
}

 


求最大公因子,用辗转相除法

gcd(m, n)
{
    while(n!=0)
    {
        t = m%n;
        m = n;
        n = t;
    }
    return m;
}


循环移位,参考http://www.cnblogs.com/atyuwen/archive/2009/11/08/rotate.html

是从某个初始元素开始,依次将其替换成其后相隔固定距离的元素。
如果后面没有足够的偏移距离了,则又返回头部继续计算(相当于求模)。
直到最后形成一个置换圈为止。

若第一步求得的最大公约数n为1,那么只需一次__rotate_cycle就可以遍历到所有的元素,
并将每个元素正确的替换为其后相距某个距离的元素,于是也就完成了循环左移操作。
若n大于1,那么每一次__rotate_cycle只能将t/n的元素正确的左移,
其中t为串的总长度,而这些被移动的元素是以d为等间距的,所以循环n次,
并分别以串的前n个元素为起点进行__rotate_cycle操作,
就能保证将所有的元素都移动到正确的位置上。

__rotate_cycle(first, last, initial, shift, T*)
{
    T value = *initial;
    RandomAccessIterator ptr1, ptr2;
    ptr1 = initial;
    ptr2 = ptr1+shift;
    while(ptr2 != initial)
    {
        *ptr1 = *ptr2;
        ptr1 = ptr2;
        if(last - ptr2 > shift)
            ptr2 += shift;
        else
            ptr2 = first + (shift - (last - ptr2));
    }
    *ptr = value;
}

 

 

rotate_copy不需要就地在原容器中调整内容
两段元素的彼此交换, 把后段复制到新容器的前段,把前段复制到新容器的后段

rotate_copy(first, middle, last, result)
{
    copy(first, middle, copy(middle, last, result));
}

 

 

search在序列一种查找序列2首次出现的位置

__search(first1, last1, first2, last2, Distance1*, Distance2*)
{
    Distance1 d1 = 0;
    Distance(first1, last1, d1);
    Distance2 d2 = 0;
    Distance(first2, last2, d2);

    //用两个序列的大小辅助进行判断,加快查找速度
    if(d1 < d2)
        return last1;

    ForwardIterator1 current1 = first1;
    ForwardIterator2 current2 = first2;

    while(current2 != last2)
    {
        if(*current1 == *current2)
        {
            ++current1;
            ++current2;
        }
        else
        {
            if(d1 == d2)//如果头部的两个元素不相等且两个序列一样长,则不可能相等
                return last1;
            else//重新调整指针,准备再次查找
            {
                current1 == ++first1;
                current2 = first2;
                --d1;//排除了一个元素所以长度要减一
            }
        }
    }
    return first1;
}

 


search_n查找连续count个符合条件的元素所形成的子序列,并返回一个迭代器指向该子序列的起始位置

search_n(first, last, count, value)
{
    if(count <= 0)
        return first;
    else
    {
        first = find(first, last, value);//找到一个符合条件的元素
        while(first != last)
        {
            int n = count - 1;
            ForwardIterator i = first;
            ++i;
            while(i!=last && n!=0 && *i==value)//依次比较之后的元素,直到找到n个
            {
                ++i;
                --n;
            }
            if(n == 0)
                return first;
            else
                first = find(i, last, value);//如果不能找到连续n个,重新找下面序列中第一个符合条件的元素
        }
        return last;
    }
}

 

 

unique移除相邻的重复元素,返回迭代器指向新区间的尾端,算法是稳定的

unique(first, last)
{
    first = adjacent_find(first, last);
    return unique_copy(first, last, first);
    //传递给unique_copy完成
}

 

 

unique_copy将符合条件的元素拷贝到result开头的区间内

unique_copy(first, last, result)
{
    if(first == last)
        return __unique_copy(first, last, result, iterator_category(result));
}
__unique_copy(first, last, result, forward_iterator_tag)
{
    *result = *first;
    while(++first != last)
    {
        if(*result != *first)
            *++result = *first;
    }
    return ++result;
}


//当目标迭代器为输出迭代器时,不能像之前那样读取目标区间中的元素值,因此需要重载一个函数

__unique_copy(first, last, result, output_iterator_tag)
{
    return __unique_copy(first, last, result, value_type(first));
}


//因为不能有*result == *first 这样的操作,因此需要另外定义一个变量,记录下写入目标容器中的元素的值
//因此需要定义一个变量value, 就需要知道元素的类型

__unique_copy(first, last, result, T*)
{
    T value = *first;
    *result = value;
    while(++first != last)
    {
        if(value != *first)
        {
            value = *first;
            *++result = value;
        }
    }
    return ++result;
}

 

posted @ 2012-04-28 14:18  w0w0  阅读(196)  评论(0编辑  收藏  举报