日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

《STL源码剖析》学习--6章--_rotate算法分析

發(fā)布時間:2025/3/21 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《STL源码剖析》学习--6章--_rotate算法分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.


最近在看侯捷的《STL源碼剖析》,其中有許多不太明白之處,后經(jīng)分析或查找資料有了些理解,現(xiàn)記錄一下。

《STL源碼剖析》學習--6章--random access iterator _rotate算法分析

針對forward iterator 和 bidirectional iterator的_rotate 比較好理解,但是對random access iterator _rotate卻難以理解,作者也沒有過多的文字講解。

參考http://www.cnblogs.com/atyuwen/archive/2009/11/08/rotate.html,這個作者有好些地方?jīng)]講清楚,再做一下細致的記錄。


先列出源碼如下:

template<class RandomAccessIterator, class Distance> void __rotate(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last, Distance*, random_access_iterator_tag) { Distance n = __gcd(last - first, middle - first); while (n--) __rotate_cycle(first, last, frist + n, middle - first, value_type(first)); } template<class EuclideanRingElement> EuclideanRingElement __gcd(EuclideanRingElement m, EuclideanRingElement n) { while (n != 0) { EuclideanRingElement t = m % n; m = n; n = t; } return m; } template<class _RandomAccessIterator, class Distance, class T> void __rotate_cycle(RandomAccessIterator first, RandomAccessIterator last, RandomAccessIterator initial, Distance shift, T*) { T value = *initial; RandomAccessIterator ptr1 = initial; RandomAccessIterator ptr2 = ptr1 + shift; while (ptr2 != initial) { *ptr1 = *ptr2; ptr1 = ptr2; if (last - ptr2 > shift) ptr2 += shift; else ptr2 = first + (shift - (last - ptr2)); } *ptr1 = value; }


涉及到三個函數(shù),晃一看還真是看不懂,慢慢來。

__gcd()利用的是輾轉相除法來計算兩個數(shù)的最大公約數(shù),之前我們數(shù)學的時候肯定學過怎么計算兩個數(shù)的最大公約數(shù),就是用的這個方法。利用的原理就是公式: gcd(a,b)=gcd(b,r),其中 r =a mod b,t = a/b。程序中當最后余數(shù)為0時,這是m和n相等,即為最大公約數(shù)。

再看__rotate_cycle(),畫圖比較容易理解問題,如下,可以理解其作用就是從某個初始化元素開始,依次將其替換成其后相隔固定距離的元素。如果后面沒有足夠的偏移距離了,則又返回頭部繼續(xù)計算(相當于求模),直到最后形成一個置換圈為止。

用數(shù)字來看,比較清楚,如果last-first長度正好是shift的倍數(shù)或者last-first和shift的最大公約數(shù)大于1時,只是幾個值之間的循環(huán)移位。而當last-first與shift互質(zhì)是就特化為循環(huán)移位操作,如下圖所示。

那么對于調(diào)用兩個函數(shù)的__rotate(),首先求出偏移距離和串總長的最大公約數(shù)n,然后循環(huán)n次,分別以串的前n個元素為起點進行__rotate_cycle操作。結束后保證元素進行了旋轉互換,其中的原理是什么呢?

查找資料。這就涉及到數(shù)論中的定理,如下《具體數(shù)學》一書4.8節(jié):

比如,若m=8,n=6,d=gcd(m,n)=2, 則{0mod 8,?6 mod 8, 12 mod 8,…,50 mod 8}即為 8/2=4個數(shù){0,2,4,6}的某個排列重復兩次,實際上就是{0,6,4,2,0,6,4,2?};當兩個數(shù)互素時,即d=1,上述式實際上為{1,2,3,…,m-1}的某個排列。


了解定理后,就很容易看出__rotate函數(shù)的內(nèi)涵了。middle-first相當于上述公式中的m,而last-first相當于n,Distance n相當于d。

若第一步求得的最大公約數(shù)d為1時,第一次進入while,n=0,即從first開始循環(huán)移(middle-first)距離,即middle所指元素移動到前面,只需一次__rotate_cycle就可以遍歷到所有的元素,并將每個元素正確的替換為其后相距某個距離的元素,于是也就完成了循環(huán)左移操作。

當n>1時,shift =middle-first=m,當每次__rotate_cycle截止的條件是又轉到了起始點,每次都是轉數(shù)組長度n的倍數(shù)k,kn mod m=0時,此時只有n/d的元素正確移位。

即那么每一次__rotate_cycle只能將n/d的元素正確的左移,其中n為串的總長度,而這些被移動的元素是以d為等間距的,所以循環(huán)d次,并分別以串的前d個元素為起點進行__rotate_cycle操作,就能保證將所有的元素都移動到正確的位置上。


再來看一下效率問題,對于random access iterator應該要比bidirectional效率要高,不然不需要這么復雜,bidirectional iterator總共需要三次反轉。

在這個新的算法中,每次__rotate_cycle需要t/n+1次賦值,n次循環(huán),所以總共只需要t+n次賦值操作,顯然是比bidirectional iterator的三次反轉的算法快許多。

總結

以上是生活随笔為你收集整理的《STL源码剖析》学习--6章--_rotate算法分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。