完美洗牌问题

You are given an array of  2n  elements

a1,a2,,an,b1,b2,bn

The task is to interleave the array, using an in-place algorithm such that the resulting array looks like

b1,a1,b2,a2,,bn,an

If the in-place requirement wasn't there, we could easily create a new array and copy elements giving an  O(n)  time algorithm.

With the in-place requirement, a divide and conquer algorithm bumps up the algorithm to be  θ(nlogn) .

So the question is:

Is there an  O(n)  time algorithm, which is also in-place?



Here is the answer which elaborates upon the algorithm from the paper linked by Joe:http://arxiv.org/abs/0805.1598

First let us consider a  Θ(nlogn)  algorithm which uses divide and conquer.

1) Divide and Conquer

We are given

a1,a2,,b1,b2,bn

Now to use divide and conquer, for some  m=θ(n) , we try to get the array

[a1,a2,,am,b1,b2,,bm],[am+1,,an,bm+1,bn]

and recurse.

Notice that the portion

b1,b2,bm,am+1,an
is a cyclic shift of

am+1,an,b1,bm

by  m  places.

This is a classic and can be done in-place by three reversals and in  O(n)  time.

Thus the divide and conquer gives you a  θ(nlogn)  algorithm, with a recursion similar to  T(n)=2T(n/2)+θ(n) .

2) Permutation Cycles

Now, another approach to the problem is the consider the permutation as a set of disjoint cycles.

The permutation is given by (assuming starting at  1 )

j2jmod2n+1

If we somehow knew exactly what the cycles were, using constant extra space, we could realize the permutation by picking an element  A , determine where that element goes (using the above formula), put the element in the target location into temporary space, put the element  A  into that target location and continue along the cycle. Once we are done with one cycle we move onto an element of the next cycle and follow that cycle and so on.

This would give us an  O(n)  time algorithm, but it assumes that we "somehow knew what the exact cycles were" and trying to do this book-keeping within the  O(1)  space limitation is what makes this problem hard.

This is where the paper uses number theory.

It can be shown that, in the case when  2n+1=3k , the elements at positions  1 3,32,,3k1 are in different cycles and every cycle contains an element at the position  3m,m0 .

This uses the fact that  2  is a generator of  (Z/3k) .

Thus when  2n+1=3k , the follow the cycle approach gives us an  O(n)  time algorithm, as for each cycle, we know exactly where to begin: powers of  3  (including  1 ) (those can be computed in  O(1) space).

3) Final Algorithm

Now we combine the above two: Divide and Conquer + Permutation Cycles.

We do a divide and conquer, but pick  m  so that  2m+1  is a power of  3  and  m=θ(n) .

So instead on recursing on both "halves", we recurse on only one and do  θ(n)  extra work.

This gives us the recurrence  T(n)=T(cn)+θ(n)  (for some  0<c<1 ) and thus gives us an  O(n)  time,  O(1)  space algorithm!



//轮换
void Cycle(int Data[],int Lenth,int Start)
{
	int Cur_index,Temp1,Temp2;

	Cur_index=(Start*2)%(Lenth+1);
	Temp1=Data[Cur_index-1];
	Data[Cur_index-1]=Data[Start-1];

	while(Cur_index!=Start)
	{
		Temp2=Data[(Cur_index*2)%(Lenth+1)-1];
		Data[(Cur_index*2)%(Lenth+1)-1]=Temp1;
		Temp1=Temp2;
		Cur_index=(Cur_index*2)%(Lenth+1);
	}
}

//数组循环移位 参考编程珠玑
void Reverse(int Data[],int Len)
{
	int i,Temp;
	for(i=0;i<Len/2;i++)
	{
		Temp=Data[i];
		Data[i]=Data[Len-i-1];
		Data[Len-i-1]=Temp;
	}
}
void ShiftN(int Data[],int Len,int N)
{
	Reverse(Data,Len-N);
	Reverse(&Data[Len-N],N);
	Reverse(Data,Len);
}

//满足Lenth=3^k-1的perfect shfulle的实现
void Perfect1(int Data[],int Lenth)
{
	int i=1;
	if(Lenth==2)
	{
		i=Data[Lenth-1];
		Data[Lenth-1]=Data[Lenth-2];
		Data[Lenth-2]=i;
		return;
	}
	while(i<Lenth)
	{
		Cycle(Data,Lenth,i);
		i=i*3;
	}
}
//查找最接近N的3^k
int LookUp(int N)
{
	int i=3;
	while(i<=N+1) i*=3;
	if(i>3) i=i/3;
	return i;
}
void perfect(int Data[],int Lenth)
{
	int i,startPos=0;
	while(startPos<Lenth)
	{
		i=LookUp(Lenth-startPos);
		ShiftN(&Data[startPos+(i-1)/2],(Lenth-startPos)/2,(i-1)/2);
		Perfect1(&Data[startPos],i-1);
		startPos+=(i-1);
	}
}
#define N 100
void main()
{
	int data[N]={0};
	int i=0;
	int n;
	printf("please input the number of data you wanna to test(should less than 100):/n");
	scanf("%d",&n);
	if(n&1)
	{
		printf("sorry,the number should be even ");
		return;
	}
	for(i=0;i<n;i++)
		data[i]=i+1;
	perfect(data,n);
	for(i=0;i<n;i++)
		printf("%d   ",data[i]);
}

还有一个解决方案:

http://blog.csdn.net/livelylittlefish/article/details/2102457

我写的代码==

inline void swap(int &x,int &y)
{
	int t=x;
	x=y;
	y=t;
};
void reverse(int A[],int n)
{
	int l=0,r=n-1;
	while(l<r)
	{
		swap(A[l],A[r]);
		++l;
		--r;
	}
}
void rotate(int A[],int n)
{
	if (n<=0)
	{
		return;
	}
	reverse(A,n);
	reverse(A+n,n);
	reverse(A,n+n);
}
void rotateMid(int A[],int n,int mid)
{
	if (n<=0)
	{
		return;
	}
	reverse(A+mid,n);
	reverse(A,n+1);
}
void permute(int A[],int n)
{
	if (n<=1)
	{
		return;
	}
	else if (n==2)
	{
		swap(A[1],A[2]);
	}
	else if (n==3)
	{
		vector<int> vec1(A,A+n*2);
		swap(A[1],A[n]);
		rotateMid(A+2,2,1);

		vector<int> vec3(A,A+n*2);
	}
	else
	{
		swap(A[1],A[n]);
		swap(A[n-1],A[2*n-2]);
		rotate(A+2,n-2);
		rotate(A+4,n-4);
		vector<int> vec(A,A+n*2);
		permute(A+4,n-4);
	}
}


参考:

http://cs.stackexchange.com/questions/332/in-place-algorithm-for-interleaving-an-array

http://blog.csdn.net/yuan8080/article/details/5705567

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值