旋转数组

#1. 问题描述

将一个具有n个元素的向量,向左旋转i个位置。

例如,具有8个元素的向量abcdefgh,向左旋转3个元素的结果是defghabc。

此题有很多解法,下面只讨论两个优美高效的解法。

#2. 经典解法

经典解法来自于《编程珠玑》,这也是大多数人使用的方法。这个解法的思路如下:

首先,将这个问题看做是把数组ab转换成ba,但同时也假定我们具有在数组中转置指定指定部分元素的函数。我们先从ab开始,转置a得到a^r b,再转置b得到 a^r b^r ,然后再转置整个a^r b^r 得到(a^r b^r )^r ,即ba,这就导致了下面产生旋转作用的代码;注释显示了abcdefgh向左旋转3个元素的结果。

reverse(0, i-1) /* cba defgh */
reverse(i, n-1) /* cba hgfed */
reverse(0, n-1) /* defghabc */

完整的代码如下:

#include <stdio.h>
#include <string.h>

void reverse(char *base, int left, int right)
{
    char *p = base + left;
    char *q = base + right;

    while ( p < q )
    {
        char temp = *p;
        *p++ = *q;
        *q-- = temp;
    }
}


int main(int argc, char* argv[])
{

    char str[] = "abcdefgh";
    int n = strlen(str);
    int i = 3;

    reverse(str, 0, i-1); printf("%s\n", str);
    reverse(str, i, n-1); printf("%s\n", str);
    reverse(str, 0, n-1); printf("%s\n", str);
    return 0;
}

#3. 创新解法

下面再来第二种解法,这种解法来自于C++ STL的reverse调用的源码,代码如下:

template <class ForwardIterator>  
  void rotate ( ForwardIterator first, ForwardIterator 	middle,  	
           	     ForwardIterator last )  	
{  	
  ForwardIterator next = middle;  	
  w	hile (first!=next)  	
  {	  	
   	 swap (*first++,*next++);  	
   	 if (next==last) next=middle;  	
    else if (first == middle) middle=next;  	
  }  
}  

上面的伪代码可能不太好理解,我们来分析一下。

假设数组有N个元素,旋转i位,且(N>i),我们首先考虑i < N-i的情况,我们可以把数组分成三部分,分别是 ab1 b2,其中,a的长度等于b1的长度,然后算法执行一轮以后,就得到 b1ab2,剩下要做的事情就是交换ab2的顺序,且中点应该在ab2交接的地方,所以有middle=next,假设此时b2的长度小于a,则将划分为a1a2b2,然后再执行一次while循环,整个数组就变成了b1b2a2a1,现在是要交换a2和a1的顺序即可。

交换a2和a1的顺序其实和交换a和b的顺序是一样的,只是元素更少了。

完整的代码如下所示:

#include <stdio.h>
#include <string.h>

void swap(char *p, char *q)
{
    if ( p == NULL || q == NULL) return;

    char temp = *p;
    *p = *q;
    *q = temp;
}


void rotate(char* first, char* middle, char* last)
{
    char *next = middle;
    while( first != next)
    {
        swap( first++, next++);
        if (next == last){ next = middle;}
        else if ( first == middle ) { middle = next;}
    }
    return;
}


int main(int argc, char* argv[])
{

   char str[] = "abcdefgh";
   int n = strlen(str);
   int i = 3;
   rotate( str, str + i, str + n);
   printf("%s\n", str);
   return 0;
}
赖明星 /
Published under (CC) BY-NC-SA in categories 算法  tagged with C语言  算法