码迷,mamicode.com
首页 > 其他好文 > 详细

STL 源码分析  之 rotate()函数分析

时间:2015-04-02 18:55:01      阅读:198      评论:0      收藏:0      [点我收藏+]

标签:c++

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		:	jasonleaster@gmail.com
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.具体的意义如何.


待更新~






技术分享




STL 源码分析  之 rotate()函数分析

标签:c++

原文地址:http://blog.csdn.net/cinmyheart/article/details/44834859

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!