|
楼主 |
发表于 2005-10-11 15:27:59
|
显示全部楼层
Post by bbbush
全忘了,依稀记得是群和群的分划,但是忘了怎么找 1-1 的函数了
N 不能整除 k 的时候会证明 O(n),分划的一点都不会了,怎么做啊?
bb兄高见,的确应当从划分的角度设计和证明。
[php]
/************************************************
把A[n]循环右移k位的时间复杂度为O(n)的C语言算法示例。
思路是把A[t]移到A[(t+k) mod n],其中t=0~n-1。
为尽量满足低空间复杂度要求,以某一元素作为移动的起
点,比如A,同时作为元素交换的枢纽,用next代表i右边
k位的元素关键字。
每次把A和A[next]交换,交换后更新next值(i不变),
然后重复交换过程,直到i等于next时为止。
考虑到类似于n=6,k=3的情况,交换进行2次后(j=2),虽然
i=next,但没有完成所有右移动作。故而此时需更新i值,即
i=i+1,然后再继续进行上面的交换过程。
可以证明,交换次数最多为n-1次;且按等k间隔对集合A[1..n]
进行划分的话,至多只有(k%n)个划分,故当i从0自增至k-1时,
应当终止外层循环。在"交换循环体"中,j的增量为j1,故当外层
循环中j+j1>=n时,也应当终止外层循环。
虽然有两个循环,但可以发现,其时间复杂度为O(n)。
*************************************************/
#include <stdio.h>
#define n 5
#define k 2
int A[n]={1,2,3,4,5};
int main()
{
int i=0; /* 数组索引关键字 */
int j=0; /* 交换次数计数器 */
int j1=0; /* 交换循环体执行完成后交换次数增量 */
int next; /* 下一个元素 */
do
{
next=(i+k)%n; /* 右边k位*/
j1=0;
/* 交换循环体 */
while(i!=next)
{
/*swapping*/
A=A+A[next];
A[next]=A-A[next];
A=A-A[next];
next=(next+k)%n;
j1++;
}
i++;
j+=j1;
}while(i<k%n && j+j1<n);
for(i=0;i<n;i++)printf("%d ",A);
printf("\nswap times=%d\n",j);
}[/php]
怎么也没办法只用两个附加变量来完成 怀疑原题有错 :confused:
哎,思维僵化了,看标准答案,真简洁:
- void RSh(int A[n],int k)//把数组A的元素循环右移k位,只用一个辅助存储空间
- {
- for(i=1;i<=k;i++)
- if(n%i==0&&k%i==0) p=i;//求n和k的最大公约数p
- for(i=0;i<p;i++)
- {
- j=i;l=(i+n-k)%n;temp=A[i];
- while(l!=i)
- {
- A[j]=A[l];
- j=l;l=(j+n-k)%n;
- }// 循环右移一步
- A[j]=temp;
- }//for
- }//RSh
复制代码 |
|