zoukankan      html  css  js  c++  java
  • 一维向量旋转算法 编程珠玑 第二章

    看了编程珠玑第二章,这里面讲了三道题目,这里说一下第二题,一维向量旋转算法。

    题目:将一个n元一维向量(例数组)向左旋转i个位置。

    解决方法:书上讲解了5种方法,自己只想起来2种最简单方法(下面讲的前两种)。

    1.原始方法。

      从左向右依次移动一位,对所有数据平移;这样循环i次,算法最坏时间复杂度达n^2.耗时不推荐。

    2.空间换时间。

      顾名思义,申请一个i长度的空间,把前i半部分放到申请空间中,再把后面的所有数据向左移动i个位置,最后把申请的空间中的数据放到后半部分。浪费空间,不推荐。

    3.杂技算法(编程珠玑叫的,另叫求模置换法)

      我们知道第一种方法,每次向左旋转一个位置(其时间正比于n),总共需要旋转i次。这个方案会消耗过多的运行时间。而求模置换的方法则是尽量让每个数一次移动到位。总体的思想是:以i为除数对n求模,将向量遍历完并一次移动到位。

      另编程珠玑讲解:移动x[0]到临时变量t,然后移动x[i]到x[0],x[2i]到x[i],依次类推,直到取到x[0](其中下标都对长度n取模);然后依次对x[1]...x[i-1]执行上面操作。

      此算法技巧性比较强,一般不大好想,代码稍微复杂,也不推荐。

      另书上有代码参考,c++形式如下:

     1 //求公约数的代码,欧几里得算法
     2 unsigned int Gcd(unsigned int a, unsigned int b)
     3 {
     4     unsigned int temp;
     5     while (b != 0)
     6     {
     7         temp = a % b;
     8         a = b;
     9         b = temp;
    10     }
    11 
    12     return a;
    13 }
    14 //对数组array[n]向左旋转rotdisk个位置
    15 void zcxShift(int array[], int n, int rotdist)
    16 {
    17     unsigned int gcd = Gcd(n, rotdist);
    18 
    19     for (int i = 0; i < gcd; i ++)
    20     {
    21         int temp = array[i];
    22         int j = i;
    23         int k;
    24         while(1)
    25         {
    26             int k = j +  rotdist;
    27             if (k >= n)
    28             {
    29                 k -= n;
    30             }
    31             
    32             if (k == i)
    33             {
    34                 break;
    35             }
    36 
    37             array[j] = array[k];
    38             j = k;
    39         }
    40         array[j] = temp;
    41     }
    42 
    43 }
    View Code

    4.分段递归交换算法

      书上介绍:旋转向量x其实就是交换向量ab的两段,得到ba(a代表x中的前i个元素)。假设a比b短,将b分为b1和b2两段,使b2有跟a相同的长度,然后交换a和b2,也就是ab1b2交换得到b2b1a,a的位置已经是最终的位置,现在的问题集中到交换b2b1这两段,又回到了原来的问题。不断递归下去,到b1和b2的长度长度相等交换即可。

      书后答案有参考代码,c++描述如下:

     1 //交换操作,如下所示
     2 //swap x[a .. a+offset-1] and x[b .. b+offset-1]
     3 void swap(int array[], int a, int b, int offset)
     4 {
     5     int temp;
     6     for (int i = 0; i < offset; i++)
     7     {
     8         temp = array[a + i];
     9         array[a + i] = array[b + i];
    10         array[b + i] = temp;
    11     }
    12 }
    13 
    14 //交换主要代码
    15 void swapShift(int *array, int n, int rotdist)
    16 {
    17     int p = rotdist;
    18     int i = p;
    19     int j = n - p;
    20 
    21     while (i != j)
    22     {
    23         if (i > j)
    24         {
    25             swap(array, p - i, p, j);
    26             i -=j;
    27         }
    28         else
    29         {
    30             swap(array, p - i, p + j - i, i);
    31             j -= i;
    32         }
    33     }
    34     swap(array, p - i, p, i);
    35 }
    View Code

    5.翻手法(也叫求逆法)【推荐算法】

      思路很简单,把x向量分成ab两部分,a是前i个元素,b是后n-i个元素,首先对a求逆,然后对b求逆,然后对整体求逆得到ba。

      同样,c++代码如下:

     1 //求逆函数
     2 void reverse(int array[], int low, int high)
     3 {
     4     int temp = 0;
     5     for(int i = low; i <= (high + low) / 2; i++)
     6     {
     7         temp = array[i];
     8         array[i] = array[high - (i - low)];
     9         array[high - (i - low)] = temp;
    10     }
    11 }
    12 //整个求逆法代码
    13 void reverseShift(int *array, int n, int rotdist)
    14 {
    15     reverse(array, 0, rotdist - 1);
    16     reverse(array, rotdist, n - 1);
    17     reverse(array, 0, n - 1);
    18 }
    View Code

      算法5,简单明了,翻手算法代码非常简短,非常容易理解,而且针对字符串的求逆也不用自己写函数,在时间和空间上都很高效。再次推荐算法5。

    另书后第五题,abc向量之翻转ac,思路同5,此处不再赘述!

  • 相关阅读:
    Spring AOP两种实现方式
    重温SQL——行转列,列转行
    SpringMVC-Spring-Hibernate项目搭建之一-- 搭建maven 项目 & servlet的demo
    Linnx 服务器中mysql 无法正常访问问题
    SpringMVC-Spring-Hibernate项目搭建之三-- freemarker & 静态资源整合
    one2many &&many2many
    SQL学习
    使用Maven导出项目依赖的jar包
    Java Hash Collision之数据生产
    HashMap出现Hash DOS攻击的问题
  • 原文地址:https://www.cnblogs.com/zCoderJoy/p/3883653.html
Copyright © 2011-2022 走看看