主要通过下面的表中例子来理解:给出了源码(《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=1 |
6 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));
}