# STL实现细节之rotate()

## 引言

STL中 rotate(first, middle, last) 函数的作用是原地把容器区间 [first, middle)（左半部分） 与 [middle, last) （右半部分)的元素互换。

## 代码全文

template <class _ForwardIterator>
_ForwardIterator
rotate_left(_ForwardIterator first, _ForwardIterator last)
{
typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
value_type tmp = move(*first);
_ForwardIterator lm1 = move(next(first), last, first);
*lm1 = move(tmp);
return lm1;
}

template <class _BidirectionalIterator>
_BidirectionalIterator
rotate_right(_BidirectionalIterator first, _BidirectionalIterator last)
{
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
_BidirectionalIterator lm1 = prev(last);
value_type tmp = move(*lm1);
_BidirectionalIterator fp1 = move_backward(first, lm1, last);
*first = move(tmp);
return fp1;
}

template <class _ForwardIterator>
_ForwardIterator
rotate_forward(_ForwardIterator first, _ForwardIterator middle, _ForwardIterator last)
{
_ForwardIterator i = middle;
while (true)
{
swap(*first, *i);
++first;
if (++i == last)
break;
if (first == middle)
middle = i;
}
_ForwardIterator r = first;
if (first != middle)
{
i = middle;
while (true)
{
swap(*first, *i);
++first;
if (++i == last)
{
if (first == middle)
break;
i = middle;
}
else if (first == middle)
middle = i;
}
}
return r;
}

template<typename _Integral>
_Integral
algo_gcd(_Integral x, _Integral y)
{
do
{
_Integral t = x % y;
x = y;
y = t;
} while (y);
return x;
}

template<typename _RandomAccessIterator>
_RandomAccessIterator
rotate_gcd(_RandomAccessIterator first, _RandomAccessIterator middle, _RandomAccessIterator last)
{
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;

const difference_type m1 = middle - first;
const difference_type m2 = last - middle;
if (m1 == m2)
{
swap_ranges(first, middle, middle);
return middle;
}
const difference_type g = algo_gcd(m1, m2);
for (_RandomAccessIterator p = first + g; p != first;)
{
value_type t(move(*--p));
_RandomAccessIterator p1 = p;
_RandomAccessIterator p2 = p1 + m1;
do
{
*p1 = move(*p2);
p1 = p2;
const difference_type d = last - p2;
if (m1 < d)
p2 += m1;
else
p2 = first + (m1 - d);
} while (p2 != p);
*p1 = move(t);
}
return first + m2;
}

template <class _ForwardIterator>
_ForwardIterator
__rotate(_ForwardIterator first, _ForwardIterator middle, _ForwardIterator last,
forward_iterator_tag)
{
if (next(first) == middle)
return rotate_left(first, last);
return rotate_forward(first, middle, last);
}

template <class _BidirectionalIterator>
_BidirectionalIterator
__rotate(_BidirectionalIterator first, _BidirectionalIterator middle, _BidirectionalIterator last,
bidirectional_iterator_tag)
{
if (next(first) == middle)
return rotate_left(first, last);
if (next(middle) == last)
return rotate_right(first, last);
return rotate_forward(first, middle, last);
}

template <class _RandomAccessIterator>
_RandomAccessIterator
__rotate(_RandomAccessIterator first, _RandomAccessIterator middle, _RandomAccessIterator last,
random_access_iterator_tag)
{
if (next(first) == middle)
return rotate_left(first, last);
if (next(middle) == last)
return rotate_right(first, last);
return rotate_gcd(first, middle, last);
}

template <class _ForwardIterator>
_ForwardIterator
rotate(_ForwardIterator first, _ForwardIterator middle, _ForwardIterator last)
{
if (first == middle)
return last;
if (middle == last)
return first;
return __rotate(first, middle, last,
typename iterator_traits<_ForwardIterator>::iterator_category());
}

## 代码结构

• 前向
• 双向
• 随机访问

rotate_left()函数作用是把容器所有元素向左（起始端）循环移动一位
rotate_right()则相反，把容器所有元素向右（末端）循环移动一位

### 前向迭代版

template <class _ForwardIterator>
_ForwardIterator
rotate_forward(_ForwardIterator first, _ForwardIterator middle, _ForwardIterator last)
{
_ForwardIterator i = middle;
while (true)
{
swap(*first, *i);
++first;
if (++i == last)
break;
if (first == middle)
middle = i;
}
_ForwardIterator r = first;
if (first != middle)
{
i = middle;
while (true)
{
swap(*first, *i);
++first;
if (++i == last)
{
if (first == middle)
break;
i = middle;
}
else if (first == middle)
middle = i;
}
}
return r;
}

template <class _ForwardIterator>
void
rotate_forward(_ForwardIterator first, _ForwardIterator middle, _ForwardIterator last)
{
_ForwardIterator i = middle;
while (true)
{
swap(*first, *i);
++first;
if (++i == last)
{
if (first == middle)
break;
i = middle;
}
else if (first == middle)
middle = i;
}
}

1. 图中middle指向B段第一个元素，A与B段等长，目标是把A段挪到最后，形成BCA的结构。这种情况下first首先到达middle，这时原来处于B段的元素已经被移动到正确的位置上，然后调整middle的位置到i的位置，然后继续对AC段进行rotate操作。

2. middle指向C段第一个元素，A与C段等长，目标是把C段挪到最前面，形成CAB的结构。这种情况下i首先到达末尾，C段元素已经就位，调整i的位置到middle，继续对BA段进行操作。

### 随机访问版

template<typename _RandomAccessIterator>
_RandomAccessIterator
rotate_gcd(_RandomAccessIterator first, _RandomAccessIterator middle, _RandomAccessIterator last)
{
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;

const difference_type m1 = middle - first;
const difference_type m2 = last - middle;
if (m1 == m2)
{
swap_ranges(first, middle, middle);
return middle;
}
const difference_type g = algo_gcd(m1, m2);
for (_RandomAccessIterator p = first + g; p != first;)
{
value_type t(move(*--p));
_RandomAccessIterator p1 = p;
_RandomAccessIterator p2 = p1 + m1;
do
{
*p1 = move(*p2);
p1 = p2;
const difference_type d = last - p2;
if (m1 < d)
p2 += m1;
else
p2 = first + (m1 - d);
} while (p2 != p);
*p1 = move(t);
}
return first + m2;
}

t<-0<-4<-8<-2<-6<-t

## 测试

i5-3210M+8G RAM
Windows 10 64bit
Visual Studio 2015 with Update3
Build target: Release x64

auto get_duration(const system_clock::time_point &start, const system_clock::time_point &fin)
{
auto duration = duration_cast<microseconds>(fin - start);
return double(duration.count()) * microseconds::period::num / microseconds::period::den;
}

int main()
{
auto n = 10;
auto data_len = 20000000;
auto middle = 19;
auto avg_a = 0.0, avg_b = 0.0;
vector<int> data_a(data_len);
vector<int> data_b(data_len);
iota(begin(data_a), end(data_a), 0);
iota(begin(data_b), end(data_b), 0);
while (--n)
{
auto start = system_clock::now();
rotate_gcd(begin(data_b), begin(data_b) + middle, end(data_b));
auto finish = system_clock::now();
avg_a += get_duration(start, finish);
cout << duration << " ";
start = system_clock::now();
rotate_forward(begin(data_a), begin(data_a) + middle, end(data_a));
finish = system_clock::now();
avg_b += get_duration(start, finish);
cout << duration << "\n";
}
avg_a /= 10;
avg_b /= 10;
cout << avg_a << " " << avg_b << " " << avg_a / avg_b << "\n";
return 0;
}

middle=19

rotate_gcd()耗时居然是rotate_forward()的6倍！

## 总结

rotate_forward()里，可以看到它对元素的访问总是从位置1到位置2再到位置3这样依次访问，CPU可以提前将后面的元素一并加载到缓存中了，免去频繁读取内存的延迟。

rotate_gcd()对缓存就没那么友好了，它总是每隔一段距离再读取下一个元素，这种做法容易造成cache miss，必须从内存中读取元素，拖慢速度。

## 参考文献

http://apprize.info/programming/mathematics/11.html

01-04 627

01-27 13万+

03-28 3730

11-05 1580

08-24 7248

09-26 1983

04-09 300

06-02 925

07-23 445

01-13 939

#### pandas常用函数之shift

©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

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