STL 源码分析 之 rotate()函数分析
rotate()函数究竟能干嘛?
http://www.cplusplus.com/reference/algorithm/rotate/?kw=rotate
上面只是大致的截图, 源码在下面给出:
// rotate and rotate_copy, and their auxiliary functions template <class _EuclideanRingElement> _EuclideanRingElement __gcd(_EuclideanRingElement __m, _EuclideanRingElement __n) { while (__n != 0) { _EuclideanRingElement __t = __m % __n; __m = __n; __n = __t; } return __m; } template <class _ForwardIter, class _Distance> _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 <class _BidirectionalIter, class _Distance> _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 <class _RandomAccessIter, class _Distance, class _Tp> _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 <iostream> #include <vector> #include <algorithm> #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<int>::iterator first, vector<int>::iterator last) { for(; first != last; first++) { cout << *first << " "; } cout << endl << endl; } /* All elements. |...front .. | ... back ...| ^ 0 offset ^ middle ^ last */ void my_rotate(vector<int>::iterator __first, vector<int>::iterator __middle, vector<int>::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<int>::iterator start = __first; cout << "The original data :" << endl; show_data(start, __last); #endif vector<int>::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<int> 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<int>::iterator it = myvector.begin(); it != myvector.end(); it++) { cout << " " << *it; } cout << endl; return 0; }
加了show_data()就很容易感性的先对算法究竟如何运作的有个初步的认识.
程序作者非常巧妙的没有用额外的内存,原地进行了数据的rotate操作.STL作者嘛~都是大牛
QAQ我真的感觉我看懂了,但是这地方我还不知道怎么简洁的表述出来.
为什么那个地方要用GCD.具体的意义如何.
待更新~