重新开贴 讨论一道算法题

Jack_Yin 2009-10-23 03:04:51
题目:将数组[a1,a2,...,an,b1,b2,...,bn],变成[a1,b1,a2,b2,...,an,bn]要求时间复杂度为O(n),并分析空间复杂度
俺实现了目标不过,时间复杂度不是O(n)(代码中函数是sort_arr2),

还有一个函数sort_arr1功能是,能将b对应的元素插入到正确的位置,但是原先a元素位置无法实现,猜想一定是有某种公式,按照这种公式移动b元素后,a元素位置也能确定,并且只需一次循环.
期待高人,搞定O(n)算法,俺实在搞不定,以后慢慢想..

#include "stdafx.h"
#include "iostream"
using namespace std;

int main(int argc, char* argv[])
{
int arr[] = {11,12,13,14,15,16,17,21,22,23,24,25,26,27};
void sort_arr1(int array[],int n);//实现将b系列元素插入到正确位置
void sort_arr2(int array[],int n);//实现功能,但是时间复杂度不符合要求
void PrintArr(int NumArr[],int n);//打印所有元素

sort_arr2(arr,7);//函数调用 注意 这里传入的参数为n,而数组元素一共有2n个元素

return 0;
}

void PrintArr(int NumArr[],int n)
{
int *p = NumArr;
while( p < NumArr+n ) cout<<*p++<<" ";
cout<<endl;
}

void sort_arr1(int array[],int n)
{
int i,j,temp;
j = 1; //从数组的第二项开始
for (i=n;i<2*n-1;i++)
{
temp = array[i-n+j];
array[i-n+j] = array[i];
array[i] = temp;
j++;
printf("第%d趟 ",j-1);
PrintArr(array,n*2);
}
}

void sort_arr2(int array[],int n)
{
int i,j,k,temp;
j = 1;
for(i=n;i<2*n-1;i++)
{
temp = array[i-n+j];//保存被b代替的a位置元素
array[i-n+j] = array[i];//用b位置元素代替a位置元素
//将当前a位置和b位置之间的所有元素后移一位
k = i;
while(k>i-n+j)
{
array[k] = array[k-1];
k--;
}
array[i-n+j+1] = temp; //后移后 出现一个空位(即当前a元素的后一个元素),用先前保存过的被b替换过的a 代替
j++;
printf("第%d趟 ",j-1);
PrintArr(array,n*2);
}
}


运行结果
第1趟 11 21 12 13 14 15 16 17 22 23 24 25 26 27
第2趟 11 21 12 22 13 14 15 16 17 23 24 25 26 27
第3趟 11 21 12 22 13 23 14 15 16 17 24 25 26 27
第4趟 11 21 12 22 13 23 14 24 15 16 17 25 26 27
第5趟 11 21 12 22 13 23 14 24 15 25 16 17 26 27
第6趟 11 21 12 22 13 23 14 24 15 25 16 26 17 27
Press any key to continue
...全文
539 29 打赏 收藏 转发到动态 举报
写回复
用AI写文章
29 条回复
切换为时间正序
请发表友善的回复…
发表回复
liutengfeigo 2010-06-27
  • 打赏
  • 举报
回复
都是算法高手啊
alphaxiang 2009-10-28
  • 打赏
  • 举报
回复
这个叫perfect shfulle
1:perfect shfulle 整个变换的实质是 i -> 2*i mod (2*n+1) ­
2:那篇文章就是利用了每个轮换里面的所有元素由一个3^k生成。每个3^k生成的轮换互不相交。
上面我已经贴出了整个实现代码了。时间复杂度O(n),空间复杂度O(1)

小弟以前写了一篇体会。
http://user.qzone.qq.com/414353346/blog/1243343118
Jack_Yin 2009-10-28
  • 打赏
  • 举报
回复
悲剧看了那篇论文还是不会,关键是看不懂
在文章第三部分 Algorithm部分由两点不明白
1.cyclic shift 怎么搞
2.cycle Leader algorithm 怎么搞
期待大虾 知道 要是能贴上代码 就最好了.谢谢.
看来 俺的基础还是太差 数学知识缺乏的很 还有算法
Jack_Yin 2009-10-28
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 new_006 的回复:]
这个叫perfect shfulle
1:perfect shfulle 整个变换的实质是    i -> 2*i mod (2*n+1) ­
2:那篇文章就是利用了每个轮换里面的所有元素由一个3^k生成。每个3^k生成的轮换互不相交。
上面我已经贴出了整个实现代码了。时间复杂度O(n),空间复杂度O(1)

小弟以前写了一篇体会。
http://user.qzone.qq.com/414353346/blog/1243343118
[/Quote]
牛 潜心研究代码ing
绿色夹克衫 2009-10-28
  • 打赏
  • 举报
回复
不好意思,长期以来形成的印象,以为是这么解呢,自己也没有验证过。
这是一道以前的google面试题,讨论过。也因此形成了错误的印象。
大家当我前面没有说,按照PDF中的方法解应该是最理想的!希望没有误导大家!

[Quote=引用 25 楼 sbwwkmyd 的回复:]
引用 24 楼 litaoye 的回复:
这题用不到PDF里面的内容就可以做到O(n)时间,O(1)空间!

因为整个置换群是一个大环,因此用贪心就可以解了,把第二项保存到一个临时变量中,
然后第二项需要有一项来填充, 填充后又空出一项... 一直计算到需要填入得数字就是第二项即可。



如果是一个环就好了,10个数就有两个环.
[/Quote]
showjim 2009-10-28
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 new_006 的回复:]
这个叫perfect shfulle
1:perfect shfulle 整个变换的实质是    i -> 2*i mod (2*n+1) ­
2:那篇文章就是利用了每个轮换里面的所有元素由一个3^k生成。每个3^k生成的轮换互不相交。
上面我已经贴出了整个实现代码了。时间复杂度O(n),空间复杂度O(1)

小弟以前写了一篇体会。
http://user.qzone.qq.com/414353346/blog/1243343118
[/Quote]
谢谢写你的体会,简单一点说利用原根只有一个环的特性,将原始序列初始化成多个确定的环.
时间复杂度应该是O(2n),因为初始化也需要开销.
showjim 2009-10-28
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 litaoye 的回复:]
这题用不到PDF里面的内容就可以做到O(n)时间,O(1)空间!

因为整个置换群是一个大环,因此用贪心就可以解了,把第二项保存到一个临时变量中,
然后第二项需要有一项来填充,  填充后又空出一项... 一直计算到需要填入得数字就是第二项即可。


[/Quote]
如果是一个环就好了,10个数就有两个环.
绿色夹克衫 2009-10-28
  • 打赏
  • 举报
回复
这题用不到PDF里面的内容就可以做到O(n)时间,O(1)空间!

因为整个置换群是一个大环,因此用贪心就可以解了,把第二项保存到一个临时变量中,
然后第二项需要有一项来填充, 填充后又空出一项... 一直计算到需要填入得数字就是第二项即可。

sjgh_1314 2009-10-26
  • 打赏
  • 举报
回复
http://arxiv.org/PS_cache/arxiv/pdf/0805/0805.1598v1.pdf
还是上边这篇文章是正解。O(n)的原地排序。
太牛了。
结贴给new_006分吧。给我点也行
Jack_Yin 2009-10-25
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 new_006 的回复:]
http://arxiv.org/PS_cache/arxiv/pdf/0805/0805.1598v1.pdf

A Simple In-Place Algorithm for In-Shuffle.
                Peiyush Jain, Microsoft Corporation.
                            July 2004

[/Quote]
十分感谢 这个不错 研究下
Jack_Yin 2009-10-25
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 deerwin1986 的回复:]
举例:1 2 3 4 a b c d
结果:1 a 2 b 3 c 4 d

规律比较明显 2后移1位 3后移2位 4后移3位
            a前移3位 b前移2位 c前移1位
此情况下 N为4
新开个数组 然后遍历原数组 先到N-1 再从N-1到0 分别向新数组的相应位置插数据
最后挨个赋值回来 解决。。。
不上代码了 没编译器。。。
[/Quote]
这样的话空间复杂度不为O(1)了啊
alphaxiang 2009-10-25
  • 打赏
  • 举报
回复
修改循环移位后的代码:

#include "stdio.h"
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);

}
void Perfect1(int Data[],int Lenth)//满足长度为3^k-1的变换
{
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;
}
}
int LookUp(int N)//查找满足不大于N的最大的3^k
{
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]);

}
wudagang0123 2009-10-25
  • 打赏
  • 举报
回复
#include <iostream>
#include <conio.h>
using namespace std;
void change_index(int nArray[],int nLen);
int main(int argc, char* argv[])
{
int nArray[] = {0,2,4,6,8,1,3,5,7,9};
change_index(nArray,10);
for(int i=0;i<10;i++)
{
cout<<nArray[i]<<" ";
}
cout<<endl;
getch();
return 0;
}
void change_index(int nArray[],int nLen)
{
int *pArray = new int[nLen];
int i = 0,j=0;
for(i=0;i<nLen/2;i++)
{
pArray[j] = nArray[i];
j += 2;
}
j = 1;
for(;i<nLen;i++)
{
pArray[j] = nArray[i];
j += 2;
}
for(i=0;i<nLen;i++)
{
nArray[i] = pArray[i];
}
delete []pArray;
}

空间复杂度为O(n)
alphaxiang 2009-10-25
  • 打赏
  • 举报
回复
重新搜了一下,参考编程珠玑上面的循环移位数组实现:用下面的循环移位数组替换上面的循环移位数组
#include <stdio.h>

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,N);
Reverse(&Data[N],Len-N);
Reverse(Data,Len);

}
int main()
{
int Test[10]={1,2,3,4,5,6,7,8,9,10};
int i=0;
ShiftN(Test,10,2);
for(i=0;i<10;i++)
printf("%d ",Test[i]);
return 0;
}
alphaxiang 2009-10-25
  • 打赏
  • 举报
回复
这个原题好像是要求时间复杂度O(n),空间复杂度O(1)
alphaxiang 2009-10-25
  • 打赏
  • 举报
回复
实现代码:不过我也不知道这个算不算O(n)的,循环移位是个需要改进的地方。
#include "stdio.h"

//循环移动1位
void RshiftOne(int Data[],int Lenth)
{
int Cur_index,Temp1,Temp2;

Cur_index=1;
Temp1=Data[Cur_index];
Data[Cur_index]=Data[0];

while(Cur_index<Lenth)
{
Temp2=Data[(Cur_index+1)%Lenth];
Data[(Cur_index+1)%Lenth]=Temp1;
Temp1=Temp2;
Cur_index++;
}
}

//轮换
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 RshiftN(int Data[],int Lenth,int N)
{
int i;

for(i=0;i<N;i++)
RshiftOne(Data,Lenth);

}

//满足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);
RshiftN(&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]);

}
deerwin1986 2009-10-24
  • 打赏
  • 举报
回复
举例:1 2 3 4 a b c d
结果:1 a 2 b 3 c 4 d

规律比较明显 2后移1位 3后移2位 4后移3位
a前移3位 b前移2位 c前移1位
此情况下 N为4
新开个数组 然后遍历原数组 先到N-1 再从N-1到0 分别向新数组的相应位置插数据
最后挨个赋值回来 解决。。。
不上代码了 没编译器。。。
alphaxiang 2009-10-24
  • 打赏
  • 举报
回复
http://arxiv.org/PS_cache/arxiv/pdf/0805/0805.1598v1.pdf

A Simple In-Place Algorithm for In-Shuffle.
Peiyush Jain, Microsoft Corporation.
July 2004
zhengjiankang 2009-10-24
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 hairetz 的回复:]
i为a的计数,j为b的计数,b按顺序插入偶数位(每次插入之前,插入位后的a全部后移一位)。

这样即可。不需排序。
[/Quote]

莫非把n个数的位置全部都加1需要的时间不是n?

这样移动n次不花费大量的时间?

要的是时间复杂度为O(n)的,这样的意义在哪呢?
  • 打赏
  • 举报
回复
确实不是O(n),除非可以改进a元素的顺移
加载更多回复(9)

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧