您的位置:首页 > 其它

对STL 中算法rotate Random access iterator 源码理解

2015-06-03 16:49 471 查看
主要通过下面的表中例子来理解:给出了源码(《STL源码解析》),结合代码看例子更容易理解

对random access iterator版rotate进行举例如:

这个算法有点像希尔排序,翻转的前部分长度是向后增量(位移量L1),翻转的后部分长度是向前增量(位移量L2),也可以将数列理解为一个环,位移量就是前部分长度值。而前后长度的最大公因子对应的值就是每次循环的初始位置,ptr1和ptr2为移动游标,ptr1从初始位置开始,而ptr2和ptr1的距离为位移量L1(前部分长度)大小,如果ptr2加上位移量L1超出数列总长度,则将ptr2位置向前移向L2大小,如果在移动后ptr2回到原定则将初始保留值赋给ptr1,推出循环。
初始状态1   2   3   4   5   6   7   8   9
L1=3,L2=6,n=3,故需要循环处理3次
n=3
1   2   6   4
  5   9   7   8   3

从第3个数开始,ptr2如果经过一系列增量回到这个初始点着跳出循环(下同)
n=2
1   5   6   4   8   9
  7   2   3

n=1
4   5   6   7   8   9
  1   2   3

初始状态

1   2   3   4
  5   6   7   8   9

L1=5,L2=4,n=1 故需要循环处理1次

n=16   7   8   9   1   2   3   4   5 
初始状态

1   2  
3   4   5   6   7
  8

L1=2,L2=6,n=2 故需要循环处理2次

n=2
1   4   3   6   5   8   7   2
n=1
3   4   5   6   7   8   1  
2
// 最大公因数,利用辗转相除法
// __gcd() 应用于 __rotate() 的 random access iterator 版
template <class EuclideanRingElement>
EuclideanRingElement __gcd(EuclideanRingElement m, EuclideanRingElement n)
{
while (n != 0) {           //这里是一个迭代
EuclideanRingElement t = m % n;
m = n;
n = t;
}
return m;
}

// rotate 的 random access iterator 版
template <class RandomAccessIterator, class Distance>
void __rotate(RandomAccessIterator first, RandomAccessIterator middle,
RandomAccessIterator last, Distance*,
random_access_iterator_tag) {
// 以下迭代器的相减操作只使用于RandomAccessIterator
// 取全长和前段(移动的位数)的最大公因数
Distance n = __gcd(last - first, middle - first);
// 链数为gcd(m,n) 。链中元素个数为n/gcd(m,n)。
while (n--)  //为了书写方便,先从最后一条链开始循环
__rotate_cycle(first, last, first + n, middle - first,
value_type(first));
}

template <class RandomAccessIterator, class Distance, class T>
void __rotate_cycle(RandomAccessIterator first, RandomAccessIterator last,
RandomAccessIterator initial, Distance shift, T*) {
T value = *initial;                 //记下链首元素的值,接下来链首元素“出列”留下一个“槽”
RandomAccessIterator ptr1 = initial;
RandomAccessIterator ptr2 = ptr1 + shift;//指向链中下一元素
while (ptr2 != initial) {
*ptr1 = *ptr2;
ptr1 = ptr2;                  //ptr1指向“槽”的位置
if (last - ptr2 > shift)   //还没有到达最后一个元素
ptr2 += shift;
else
ptr2 = first + (shift - (last - ptr2)); //此处可以将这个代数式解开发现如:ptr2=ptr2-翻转第二部分的长度 这样就非常好了理解了
}
*ptr1 = value;
}

// 分派函式(dispatch function)
template <class ForwardIterator>
inline void rotate(ForwardIterator first, ForwardIterator middle,
ForwardIterator last) {
if (first == middle || middle == last) return;         //交换的中间点在首尾,返回
__rotate(first, middle, last, distance_type(first),
iterator_category(first));
}

//_copy版本的rotate
template <class ForwardIterator, class OutputIterator>
OutputIterator rotate_copy(ForwardIterator first, ForwardIterator middle,
ForwardIterator last, OutputIterator result) {
return copy(first, middle, copy(middle, last, result));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息