数组循环移位

问题描述:

对于一个含有n个元素的数组a,将它的所有元素向后移动k位。


解决方案:

1最笨最直接的方法,就是把数组移动k次,每一次都把数组的所有元素向后移动一位,时间复杂度为O(k*n)。具体代码如下:
void First_kind(int a[],int n,int k)
{
	k%=n;
	while(k--)///////////////移动k次,每次都将所有元素向后移动一位。
	{
		int t=a[n-1];
		for(int i=n-1;i>0;i--)
			a[i]=a[i-1];
		a[0]=t;
	}
}


2、可以用空间换时间的思想对方法1进行优化,即另外开辟一个一样大的数组b,把a移位复制到b,再逐个把元素赋值到a。时间复杂度为O(n)。具体代码如下:
void Second_kind(int a[],int n,int k)
{
	int b[256];
	for(int i=0;i<n;i++)
		b[i]=a[(i-k+n)%n];/////////////////////将数组a的元素移位后赋给b
	for(i=0;i<n;i++)
		a[i]=b[i];
}


3、对方法1进行更进一步的优化,我们可以只移动一次,将每个元素一次向后移动k位,时间复杂度为O(n)。
例如a={1,2,3,4,5,6,7,8},n=8,要向后移k=3位。则先令t=a[0],然后a[0]=a[(0-3+8)%8]=a[4],a[4]=[(4-                3+8)%8]=a[1],,,即a[i]=a[(i-k+n)%n]。
注意:当k=4时,t=a[0],a[0]=a[4],a[4]=t。此时如果还是i=(i-k+n)%n的话将产生重复移位。此时应该令i=j+1(j为      移位的起始位置)开始继续移位,即t=a[1],a[1]=a[5],a[5]=t。。。。。
具体代码如下:
void Third_kind(int a[],int n,int k)
{
	int i,j,t,m;////////////////////////////t用来存放起始的元素值,j用来存放起始的位置,m用来记录移动的元素数,当m==n时表示移动完成。
	k%=n;
	for(m=i=j=0,t=a[i];m<n;m++)
	{
		if((i-k+n)%n==j)///////////////////如果i的下一个结点是j,但j元素已经移动过了的,值在t里面,则令a[i]=t,i从j+1的位置继续移动。
		{
			a[i]=t;
			i=++j;
			t=a[i];
			continue;
		}
		a[i]=a[(i-k+n)%n];
		i=(i-k+n)%n;
	}
}


4、这种方法算是通过取巧的方法,比较少人会想到。时间复杂度也是O(n)。
例如a={1,2,3,4,5,6,7,8},n=8,要向后移k=3位。我们可以按如下步骤移:
   a、将数组分成两段,"1,2,3,4,5" 和 "6,7,8"
   b、把这两段分别逆序,则a数组变成"5,4,3,2,1,8,7,6"
   c、把数组a整段逆序,则a变成了"6,7,8,1,2,3,4,5",这不就是我们要的答案了吗!
具体代码如下:
void Change(int *a,int i,int j)//////////////////////////函数Change实现数组a从i元素到j元素逆序。
{
	for(;i<j;i++,j--)
	{
		int t=a[i];
		a[i]=a[j];
		a[j]=t;
	}
}

void Fourth_kind(int *a,int n,int k)
{
	Change(a,0,n-k-1);
	Change(a,n-k,n-1);
	Change(a,0,n-1);
}
原文地址:https://www.cnblogs.com/Bone-ACE/p/4531310.html