n元一维向量旋转问题(编程珠玑--第2章--问题B )

来源:互联网 发布:大华数据恢复 编辑:程序博客网 时间:2024/04/29 03:28

在《编程珠玑 第二版》第2章中作者给出了3个问题,其中问题B是说:能否在仅使用数十个额外字节的存储空间的情况下,在正比于n的时间内,将一个n元一维向量x向左旋转i个位置。例如:当n=8且i=3时,向量abcdefgh旋转为defghabc。

在该问题中,作者随后给出了几种解决思路,并分析了各种方法的优缺点。

思路一:使用的一个临时数组,将要移动的向量x的前i个元素复制到这个临时数组中,然后将剩下的n-i个元素向左移动i个位置,最后将最初的i个元素从临时数组中复制到向量x中余下的位置。这种方法的缺点是显然易见的,需要额外的i个存储空间,产生了过大的存储空间的消耗。

思路二:定义一个函数将向量x向左旋转一个位置(其时间正比于n)然后调用该函数i次。该方法的缺点是:由于要进行i次调用,产生过多的运行时间。

思路三:先将x[0]存储到一个临时变量temp中,然后移动x[i]到x[0],x[2i]到x[i],x[3i]到x[2i]依此类推(其中x中所有的坐标都需对n取模),直到当x[(k*i)%n]中k*i%n取回0时,然后取而代之以temp值移动到x[(k-1)*i%n]终止该过程。如果该过程没有移动全部元素,就从x[1]开始重复上述过程,直到所有的元素都已经移动为止。

思路四:利用旋转法,将要旋转的向量x可看成是ab,其中a代表x中的前i个元素,则旋转向量x其实就是交换向量ab的两端,得到向量ba。书中提到我们可以先对a求逆得到(a)Tb,再对b求逆得到(a)T(b)T,然后整体求逆((a)T(b)T)T,记得ba。

本文中给出了思路三和思路四的解法,思路三的程序执行流程为:


其中,置换轮次为什么为旋转位数和向量长度的最大公约数,这里有一篇写的比较好的博文,大家可以参考:http://kb.cnblogs.com/page/88517/

以下为代码:

#include "stdafx.h"#include <string>#include <iostream>using namespace std;int gcd(const int& a, const int& b);void VectorRotation(char* str, const int& step, const int& Len);void Reverse(char* str, const int& Len);void VectorRotation_Reverse(char* str, const int& step, const int& Len);int _tmain(int argc, _TCHAR* argv[]){char str[] = "abcdefghijklmnopqrstuvwxyz";cout<<"the raw string is: "<<str<<endl<<endl;/*VectorRotation(str, 3, strlen(str));cout<<"the string Rotation Left 11 postion is: "<<str<<endl;*/VectorRotation_Reverse(str, 3, strlen(str));cout<<"the string Rotation Left 3 postion is: "<<str<<endl;for(;;);return 0;}/******************************************************************************************************Function:VectorRotation(char* str, int& i)*Author:Sky*Descrition:向量左旋转i个位置(杂技算法,对于字符来说只需一个字节的额外存储空间)*Access Level:*Input:str: 旋转向量step:旋转位移量Len: 字符串长度*Output:NULL*Return:NULL*****************************************************************************************************/void VectorRotation(char* str, const int& step, const int& Len){char temp = ' ';int j = 0;//置换索引int k = 0;//当前待置换的位置int round = gcd(step, Len);//置换轮次for(int i=0; i!=round; i++){temp = str[i];do{str[(j*step+i)%Len] = str[((j+1)*step+i)%Len];j++;k = ((j+1)*step+i)%Len;}while(i != k);//直至返回到取str[i]中的元素str[(j*step+i)%Len] = temp;j = 0;//复位,为下一轮次做准备}}/******************************************************************************************************求两个数的最大公约数 欧几里得算法又叫辗转相除法* m=n*q+r; gcd(m,n)=gcd(n,r);******************************************************************************************************/int gcd(const int& a, const int& b){if(0 == b)return a;else{int Remainder = a%b;return gcd(b, Remainder);}}/************************************************************************************************* 3、反转算法 AB  ((A)T(B)T)T=BA*************************************************************************************************/void VectorRotation_Reverse(char* str, const int& step, const int& Len){Reverse(str, step);Reverse(str+step, Len-step);Reverse(str, Len);}void Reverse(char* str, const int& Len){char* first = str;char* last = str+Len-1;char temp = ' ';while(first < last){//switchtemp = *first;*first = *last;*last = temp;//nextfirst++;last--;}}


程序执行结果:




0 0
原创粉丝点击