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.具体的意义如何.

待更新~

时间: 2024-08-07 18:10:22

STL 源码分析  之 rotate()函数分析的相关文章

《STL源码剖析》--next_permutation函数

STL中提供了2个计算排列组合关系的算法.分别是next_permucation和prev_permutaion. next_permutation是用来计算下一个(next)字典序排列的组合,而prev_permutation用来计算上一个(prev)字典序的排列组合. 字典排序是指排列组合中,按照大小由小到大的排序,例如123的排列组着,字典排序为123,132,213,231,312,321. 看一下next_permutation的实现原理: 从序列的后面向前找,找了两个相邻的元素p[n

STL源码笔记(12)—序列式容器之deque(二)

STL源码笔记(12)-序列式容器之deque(二) 再谈deque数据结构 我们知道deque是通过map管理很多个互相独立连续空间,由于对deque_iterator的特殊设计,使得在使用的时候就好像连续一样.有了deque_iterator的基础(例如重载的操作符等),对于我们实现容器的一些方法就十分方便了.与vector一样,deque也维护一个start,和finish两个迭代器,start指向容器中的一个元素,finish指向最后一个元素的后一个位置(前闭后开),从微观上讲,star

stl源码分析之hash table

本文主要分析g++ stl中哈希表的实现方法.stl中,除了以红黑树为底层存储结构的map和set,还有用哈希表实现的hash_map和hash_set.map和set的查询时间是对数级的,而hash_map和hash_set更快,可以达到常数级,不过哈希表需要更多内存空间,属于以空间换时间的用法,而且选择一个好的哈希函数也不那么容易. 一. 哈希表基本概念 哈希表,又名散列表,是根据关键字直接访问内存的数据结构.通过哈希函数,将键值映射转换成数组中的位置,就可以在O(1)的时间内访问到数据.举

STL源码分析--仿函数 &amp; 配接器

STL源码分析-仿函数 & 配接器 仿函数就是函数对象.就实现观点而言,仿函数其实就是一个"行为类似函数"的对象.为了能够"行为类似函数",其类别定义中必须自定义(或说改写.重载)function call 运算子(operator()),拥有这样的运算子后,我们就可以在仿函数的对象后面加上一对小括号,以此调用仿函数所定义的operator().仿函数作为可配接的关键因素. 配接器在STL组件的灵活组合运用功能上,扮演着轴承.转换器的角色,adapter的定

STL源码分析--萃取编程(traits)技术的实现

1.为什么要出现? 按照默认认定,一个模板给出了一个单一的定义,可以用于用户可以想到的任何模板参数!但是对于写模板的人而言,这种方式并不灵活,特别是遇到模板参数为指针时,若想实现与类型的参量不一样的实例化,就变得不太可能了!也有时,想禁止此种相同的实例化变得不太可能!故而出现了,Partial Specialization! 同时,在使用void*指针时,可以最大限度的共享代码,减少代码的膨胀! 2.它是什么?其实,就是用户定义的偏特化.用template<>来说明这是一个偏特化,针对任何模板

stl源码分析之vector

上篇简单介绍了gcc4.8提供的几种allocator的实现方法和作用,这是所有stl组件的基础,容器必须通过allocator申请分配内存和释放内存,至于底层是直接分配释放内存还是使用内存池等方法就不是组件需要考虑的事情.这篇文章开始分析gcc4.8 stl的容器源码实现.stl的容器分为序列式容器和关联式容器,前者包括vector,list,queue以及stack等常用数据结构,后者包含了map,set以及hash table等比较高级的结构,本文就从使用最广泛也是最基础的vector开始

STL源码分析--空间配置器的底层实现 (二)

STL源码分析-空间配置器 空间配置器中门道 在STL中的容器里都是使用统一的空间配置器,空间配置器就是管理分配内存和销毁内存的.在STL将在heap空间创建一个对象分为两个步骤,第一是申请一块内存,第二是在这块内存中初始化一个对象.首先申请空间是由malloc提供,初始化一个对象时由constructor管理.销毁一个对象也是由两步骤完成,第一是销毁空间上的对象,第二是释放这块内存. 同时,STL的空间配置器分为两级内存,如果申请的内存空间大于128KB,那么就使用第一级空间配置,如果小于,那

STL源码分析--仿函数 &amp; 模板的模板参数 &amp; 临时对象

STL源码分析-使用的一些特殊语法 关于泛型编程中用到的一些特殊语法,这些语法也适用于平常的模板编程 1.  类模板中使用静态成员变量 Static成员变量在类模板中并不是很特殊,同时这个变量不属于对象,属于实例化以后的这个类类型.每一个实例化对应一个static变量 2.  类模板中可以再有模板成员 3.  模板参数可以根据前一个模板参数而设定默认值 4.  类模板可以拥有非类型的模板参数 所谓非类型的模板参数就是内建型的模板参数 Template <class T,class Alloc =

STL 源码分析 # stl_iterator &amp; stl_iterator_base #

STL 源码分析 # stl_iterator_base && stl_iterator # 这里能很清楚的看到各个基础类型的继承关系 template <class _Tp, class _Distance> struct input_iterator { typedef input_iterator_tag iterator_category; typedef _Tp value_type; typedef _Distance difference_type; typede

stl源码分析之list

本文主要分析gcc4.8版本的stl list的源码实现,与vector的线性空间结构不同,list的节点是任意分散的,节点之间通过指针连接,好处是在任何位置插入删除元素都只需要常数时间,缺点是不能随机访问,查询复杂度是O(n),n为list中的元素个数.所以list非常适合应用与数据插入删除频繁的场景. 一. list节点 list节点定义如下, struct _List_node_base { _List_node_base* _M_next; _List_node_base* _M_pre