編程珠璣:向量旋轉(旋轉交換)

問題描述 數組

請將一個具備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獲得(arbrr,實際上就是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);
}
相關文章
相關標籤/搜索