向量旋转算法(Java实现)

来源:互联网 发布:windows nginx tomcat 编辑:程序博客网 时间:2024/05/09 02:49

 

          向量旋转问题:给定一个 n维向量, 求 将它向左循环移动i位后的向量。比如:[1,2,3,4,5]向左循环移动3位后,变成[4,5,1,2,3]。为了简单起见,向量采用数组表示。

 

           本文讨论的内容参见《编程珠玑I(第二版)的第二章。在那里,讨论了向量旋转的四种算法:

 

           1.基于数组移动的思路: 这个是比较简单的,即将要移动的i个元素复制到一个临时数组中,然后,将原数组的n-i个元素依次复制到前n-i个位置上,最后,将临时数组中的i个元素移动到原数组的末尾i个位置上。该思路实现简单,运行时间效率为O(n),空间效率是O(i);当i较大时,会有较大的空间消耗。

 

           图示:[1,2,3,4,5] --->[4,5,3,4,5] ---> [4,5,1,2,3]

                                      |--->临时数组:[1,2,3]-------- >|

 

           2.基于跳跃交换元素的思路:

       实际上,也是比较直观的。例如,[1,2,3,4,5]I= 3.直观的想法, 4肯定要到1的位置上; 那么谁到4的位置上呢?这需要将数组想像成一个环形(类似循环队列),在逻辑上通常是取模操作。[1,2,3,4,5,1,2,3,4,5],显然,24的位置。2 = (4+3) % 5.接着,52的位置;(5+3) % 5 = 3 5的位置;(3+3)% 5 = 13的位置。这样形成了一个跳跃链:[1<4<2<5<3<1]

      即:arr[1] = arr[4]; arr[4] = arr[2]; arr[2] = arr[5]; arr[5] = arr[3]; arr[3] = arr[1].这样跳跃交换后,得到最终结果: [4,5,1,2,3]

 

          nI具有大于1的最大公约数时,情形略有所不同。例如,[1,2,3,4,5,6], I = 4.需要分两轮(轮数是ni的最大公约数):

          S1:arr[1] = arr[5] , arr[5] = arr[3], arr[3] = arr[1] ,

          S2:arr[2] = arr[6], arr[6] = arr[4], arr[4] = arr[2].

      至此,也得到最终结果:[5,6,1,2,3,4]

 

 

           后面两种思路基于同一个观察结果:向量旋转实际上就是将 AB转换为BA的过程。

 

           3. 基于数组区域交换的思路:AB---> BA

           (1)AB长度相等,则将数组区域AB交换即可;

           (2)A的长度小于B,则将B分成两部分BlBr其中Br的长度与A相等。则AB= ABlBr. 交换数组区域ABr,得到BrBlA,此时,A已经在最终位置。问题转换为:将向量BrBl左移 length(Br)位;即原问题的更小规模形式,可递归求解;

           (3)A的长度大于B,则将A分成两部分AlAr,其中,Al的长度与B相等。则AB= AlArB. 交换数组区域 AlB,得到BArAl,此时,B已经在最终位置上,问题转换为:将向量ArAl左移 length(Ar)位;即原问题的更小规模形式,可递归求解。

 

           图示:[1 2 3 4 5 6 7 89 10] ,  n=10, I = 3 ; 


           S1: A=[1,2,3] , B=[4,5,6,7,8,9,10] ; A < B.

           根据(2)---> [1 2 3 | 4 5 6 7 | 8 9 10] --->  [89 10 | 4 5 6 7 | 1 2 3]

       n = 7, I = 3; [1 2 3]已在最终位置;

           第一趟结果:[89 10 4 5 6 7 * 1 2 3] ; n = 7; I =3

 

            S2:A = [8,9,10] , B= [4,5,6,7] ; A < B

            根据(2)---> [8 9 10 | 4 | 5 6 7] ---> [5 6 7 | 4 | 8 9 10]

             n= 4, I = 3; [8,9,10] 已在最终位置;

            第二趟结果:[56 7 4 * 8 9 10 1 2 3] ; n = 4, I = 3

 

            S3:A=[5,6,7] , B = [4] ; A > B

            根据(3)---> [5 | 6,7 | 4] ---> [4 | 6,7 | 5]

       n = 3, i = 2 ; [4]已在最终位置。

           第三趟结果:[4 *67 5 * 8 9 10 1 2 3] ; n = 3, I = 2

 

             S4:A=[6,7] , B= [5] ; A > B

            根据(3)---> [6 | 7 | 5] ---> [5 | 7 | 6]

        n = 2, I = 1; [5]已在最终位置

             第四趟结果:[4 5 *7 6 * 8 9 10 1 2 3] ; n = 2, I = 1

 

             S5:A= [7] , B= [6] ; A=B

             根据(1)---> [6,7]算法结束。至此所有元素都在其位置上。

             第五趟结果:[4 5 6 78 9 10 1 2 3]

 

 

           4. 基于数组逆置的思路:一个非常优雅而简单的公式:(arbr)r=ba,类似于对偶律,可用数学归纳法证明。这意味着,只要将a部分逆置,然后将b部分逆置,最后将整个部分逆置,就得到了所期望的结果。算法简单,优雅,并且高效,不易出错;时间效率是O(n),空间效率是O(1)。这说明,掌握一定的计算机科学知识和方法对于程序设计是非常重要的。

 

            图示:[1,2,3,4,5] --->[3,2,1,4,5] ---> [3,2,1,5,4] ---> [4,5,1,2,3]

 

       Java 实现代码:

 

       

 

 

         

 

原创粉丝点击