STL 源码分析 之 rotate()函数分析
rotate()函数究竟能干嘛?
http://www.cplusplus.com/reference/algorithm/rotate/?kw=rotate
上面只是大致的截图, 源码在下面给出:
// rotate and rotate_copy, and their auxiliary functions
template
_EuclideanRingElement __gcd(_EuclideanRingElement __m,
_EuclideanRingElement __n)
{
while (__n != 0) {
_EuclideanRingElement __t = __m % __n;
__m = __n;
__n = __t;
}
return __m;
}
template
_ForwardIter __rotate(_ForwardIter __first,
_ForwardIter __middle,
_ForwardIter __last,
_Distance*,
forward_iterator_tag) {
if (__first == __middle)
return __last;
if (__last == __middle)
return __first;
_ForwardIter __first2 = __middle;
do {
swap(*__first++, *__first2++);
if (__first == __middle)
__middle = __first2;
} while (__first2 != __last);
_ForwardIter __new_middle = __first;
__first2 = __middle;
while (__first2 != __last) {
swap (*__first++, *__first2++);
if (__first == __middle)
__middle = __first2;
else if (__first2 == __last)
__first2 = __middle;
}
return __new_middle;
}
template
_BidirectionalIter __rotate(_BidirectionalIter __first,
_BidirectionalIter __middle,
_BidirectionalIter __last,
_Distance*,
bidirectional_iterator_tag) {
__STL_REQUIRES(_BidirectionalIter, _Mutable_BidirectionalIterator);
if (__first == __middle)
return __last;
if (__last == __middle)
return __first;
__reverse(__first, __middle, bidirectional_iterator_tag());
__reverse(__middle, __last, bidirectional_iterator_tag());
while (__first != __middle && __middle != __last)
swap (*__first++, *--__last);
if (__first == __middle) {
__reverse(__middle, __last, bidirectional_iterator_tag());
return __last;
}
else {
__reverse(__first, __middle, bidirectional_iterator_tag());
return __first;
}
}
/*
All elements.
|...front .. | ... back ...|
^ 0 offset ^ middle ^ last
*/
template
_RandomAccessIter __rotate(_RandomAccessIter __first,
_RandomAccessIter __middle,
_RandomAccessIter __last,
_Distance *, _Tp *) {
__STL_REQUIRES(_RandomAccessIter, _Mutable_RandomAccessIterator);
_Distance __n = __last - __first; // The number of all elements
_Distance __k = __middle - __first; // The front elements
_Distance __l = __n - __k; // The back elements
_RandomAccessIter __result = __first + (__last - __middle);
if (__k == 0)
return __last;
else if (__k == __l) {
swap_ranges(__first, __middle, __middle);
return __result;
}
_Distance __d = __gcd(__n, __k);
for (_Distance __i = 0; __i < __d; __i++) {
_Tp __tmp = *__first;
_RandomAccessIter __p = __first;
if (__k < __l) {
/*
In this case, elements of the back part
is more than the front's.
*/
for (_Distance __j = 0; __j < __l/__d; __j++) {
if (__p > __first + __l) {
*__p = *(__p - __l);
__p -= __l;
}
*__p = *(__p + __k);
__p += __k;
}
}
else {
for (_Distance __j = 0; __j < __k/__d - 1; __j ++) {
if (__p < __last - __k) {
*__p = *(__p + __k);
__p += __k;
}
*__p = * (__p - __l);
__p -= __l;
}
}
*__p = __tmp;
++__first;
}
return __result;
}
想自己调试,反正代码也不长,拷贝了稍微修改一下就能用了.
认认真真看过上面的源码,会发现,我做的改动非常非常小.
我添加了一个宏定义开关,DEBUG,写了一个show_data函数,方便查看数据的变化
/************************************************
Programmer : EOF
e-mail : [email protected]
Date : 2015.04.02
File : rotate.cpp
*************************************************/
#include
#include
#include
#define DEBUG
using namespace std;
int __gcd(int __m, int __n)
{
int __t = 0;
while (__n != 0) {
__t = __m % __n;
__m = __n;
__n = __t;
}
return __m;
}
void show_data(vector::iterator first, vector::iterator last)
{
for(; first != last; first++)
{
cout << *first << " ";
}
cout << endl << endl;
}
/*
All elements.
|...front .. | ... back ...|
^ 0 offset ^ middle ^ last
*/
void my_rotate(vector::iterator __first,
vector::iterator __middle,
vector::iterator __last)
{
int __n = __last - __first; // The number of all elements
int __k = __middle - __first; // The front elements
int __l = __n - __k; // The back elements
if (__k == 0)
return ;
int __d = __gcd(__n, __k);
#ifdef DEBUG
vector::iterator start = __first;
cout << "The original data :" << endl;
show_data(start, __last);
#endif
vector::iterator __p;
for (int __i = 0; __i < __d; __i++) {
int __tmp = *__first;
__p = __first;
if (__k < __l) {
/*
In this case, elements of the back part
is more than the front's.
*/
for (int __j = 0; __j < __l / __d; __j++) {
/*
** It's so fantastic !!
*/
if (__p > __first + __l) {
*__p = *(__p - __l);
__p -= __l;
}
*__p = *(__p + __k);
__p += __k;
#ifdef DEBUG
cout << "i: " << __i << " j: " << __j << endl;
show_data(start, __last);
#endif
}
}
else {
for (int __j = 0; __j < __k / __d - 1; __j++) {
if (__p < __last - __k) {
*__p = *(__p + __k);
__p += __k;
}
*__p = * (__p - __l);
__p -= __l;
#ifdef DEBUG
cout << "i: " << __i << " j: " << __j << endl;
show_data(start, __last);
#endif
}
}
*__p = __tmp;
++__first;
}
return ;
}
int main()
{
vector myvector;
//set some values;
for (int i = 0; i < 9; i++)
{
myvector.push_back(i);
}
my_rotate(myvector.begin(),
myvector.begin() + 3,
myvector.end());
cout << "myvector contains:";
for (vector::iterator it = myvector.begin();
it != myvector.end();
it++)
{
cout << " " << *it;
}
cout << endl;
return 0;
}
加了show_data()就很容易感性的先对算法究竟如何运作的有个初步的认识.
程序作者非常巧妙的没有用额外的内存,原地进行了数据的rotate操作.STL作者嘛~都是大牛
QAQ我真的感觉我看懂了,但是这地方我还不知道怎么简洁的表述出来.
为什么那个地方要用GCD.具体的意义如何.
待更新~