問題描述 數組
請將一個具備n個元素的一維向量向左旋轉i個位置。例如,假設n=8,i=3,那麼向量abcdefgh旋轉以後獲得向量defghabc。簡單編碼使用一個具備n個元素的中間向量分n步便可完成此做業。你能夠僅使用幾十字節的微小內存,花費與n成比例的時間來旋轉該向量嗎? 函數
解決思路 編碼
方案一: code
將向量x中的前i個元素複製到一個臨時數組中,接着將餘下的n-i個元素左移i個位置,而後再將前i個元素從臨時數組中複製回x中的後面位置。 遞歸
該方案使用了i個額外的位置,如i足夠大,過於浪費空間。 內存
方案二: io
定義一個函數來將x向左旋轉一個位置,而後調用該函數i次。 class
該方案須要將數組移到i將,過於浪費時間。 效率
方案三: 變量
先將x[0]移臨時變量t中,而後將x[i]移到x[0]中,x[2i]移到x[i]中,依次類推,直到咱們又回到從x[0]中提取元素,不過在這時咱們要從t中提取元素,而後結束該過程。當i=3,n=12時,該階段將如下面的次序移到各個元素。
若是該過程不能移動全部的元素,那麼咱們再從x[1]開始移動,一直依次進行下去,直到移動了全部的元素時爲止。
該方案過於精巧,像書中所說的同樣堪稱巧妙的雜技表演,很是容易出錯。
方案四:
旋轉向量x實際上就是將向量ab的兩個部分交換爲向量ba,這裏a表明x的前i個元素。假設a比b短。將b分割成bl和br,使br的長度和a的長度同樣。交換a和br,將ablbr轉換成brbla。由於序列a已在它的最終位置了,因此咱們能夠集中精力交換b的兩個部分了。因爲這個新問題和原先的問題是同樣的,因此咱們以遞歸的方式進行解決。
該方案要求編碼細膩,還須要深思熟慮,以確保程序具備足夠的效率。
方案五:(最佳)
將這個問題看做是把數組ab轉換成數組ba吧,但同時也假定咱們具備在數組中轉置指定部分元素的函數。咱們先從ab開始,轉置a獲得arb,再轉置b獲得arbr,而後再轉置整個arbr獲得(arbr)r,實際上就是ba。
reverse(0, i-1) /*cbadefgh*/
reverse(i, n-1) /*cbahgfed*/
reverse(0, n-1) /*defghabc*/
該轉置代碼在時間和空間上都頗有效,而且是這麼簡短和簡單,想出錯都很難。
書中還提供了將10個元素的數組向上旋轉5個位置的手搖法例子:先是掌心對着你本身,左手在右手上面,如圖所示
代碼實現
#include <stdio.h> void swap(int *p, int *q); void reverse(int *vector, int index_begin, int index_end); void revrot(int *vector, int len, int step); int main(int argc, char **argv) { int step = 3; int i = 0; int vector[1024] = {1,2,3,4,5,6,7,8}; revrot(vector, 8, step); printf("after revolve: "); for(i = 0; i < 8; i++) { printf("%d ", vector[i]); } printf("\n"); } void swap(int *p, int *q) { int temp; temp = *p; *p = *q; *q = temp; } void reverse(int *vector, int index_begin, int index_end) { while(index_begin < index_end) { swap(vector + index_begin, vector + index_end); index_begin++; index_end--; } } void revrot(int *vector, int len, int step) { reverse(vector, 0, step - 1); reverse(vector, step, len - 1); reverse(vector, 0, len - 1); }