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; }