STL左旋轉字串Rotate的深入理解和自我實現
阿新 • • 發佈:2019-02-11
STL對左旋轉字串針對三種不同資料結構進行了不同的實現。
對單向連結串列採用的是同步位移,雙向連結串列是三次翻轉,都很簡單,主要看看針對隨機存取的陣列做的迴圈位移實現。
STL這個版本的原始碼如下:
__gcd是求兩個數的最大公約數,也是迴圈位移的遍數。template <class RandomAccessIterator, class Distance> void __rotate(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last, Distance*, random_access_iterator_tag) { // gcd是求最大公約數的函式。 Distance n = __gcd(last - first, middle - first); while (n--) // 需要執行__rotate_cycle n次。 __rotate_cycle(first, last, first + n, middle - first, value_type(first)); } 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; } template <class EuclideanRingElement> EuclideanRingElement __gcd(EuclideanRingElement m, EuclideanRingElement n) { while (n != 0) { EuclideanRingElement t = m % n; m = n; n = t; } return m; }
舉個例子來說明演算法過程,陣列123456789,把123翻轉到右邊,*first=1,*last=9,*middle=4;
要旋轉字串(123)的長度為3,字串長度為9,3和9的最大公約數為3,因此需要翻轉3遍;
第一遍從*(initial+shift)=6開始,6移到3的位置,9移到6的位置,下一個位置是ptr2 = first + (shift - (last - ptr2))=0+(3-(8-8))=3,不滿足ptr2 != initial的條件,退出迴圈,然後*ptr1 = value,即把數字3移動到數字9的位置,從而完成了3,6,9三個數字的位移,下面的2遍迴圈則分別完成2,5,8和1,4,76個數字的位移,最後得到最終結果456789123。
整個演算法過程可用下圖表示:
自我實現C++的int版:
#include <iostream> using namespace std; int __gcd(int a, int b) { while (b) { int tmp = a%b; a = b; b = tmp; } return a; } void __rotate_cycle(int *data, int first, int last, int initial, int shift) { int val = data[initial]; int pos1 = initial; int pos2 = initial + shift; while (pos2 != initial) { data[pos1] = data[pos2]; pos1 = pos2; pos2 = (pos2 + shift) % (last - first + 1); } data[pos1] = val; } void __rotate(int *data,int first, int middle, int last) { int gcd = __gcd(last - first+1, middle - first); cout << "迴圈位移" << gcd << "遍" << endl; while (gcd--) { __rotate_cycle(data, first, last, first + gcd, middle - first); } } void main() { int data1[10] = {1,2,3,4,5,6,7,8,9,10}; __rotate(data1, 0, 3, 9); for (int i = 0; i < 10; i++) { cout << data1[i] << " "; } cout << endl; int data2[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; __rotate(data2, 0, 4, 9); for (int i = 0; i < 10; i++) { cout << data2[i] << " "; } cout << endl; int data3[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; __rotate(data3, 0, 5, 9); for (int i = 0; i < 10; i++) { cout << data3[i] << " "; } cout << endl; int data4[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; __rotate(data4, 0, 6, 9); for (int i = 0; i < 10; i++) { cout << data4[i] << " "; } int c = 0; cin >> c; }
執行結果: