题目如下:有一个长度为2n的数组{a1,a2,a3……an,b1,b2,b3……bn},希望排序后{a1,b1,a2,b2,a3,b3……an,bn},要求时间复杂度O(n),空间复杂度O(1)。
分析:这题的难度在于空间复杂度O(1)。
有些朋友可能会想只需要从0和n/2处依次取数轮流放入新数组就能完成排序,但是这样空间复杂度就需要O(n)了,所以新建数组是不可行的,要想保持空间复杂度O(1),只能使用有限数目的变量,通过换项的方式来完成任务。
数组名我们就它叫arr[]吧~根据要求:
ai(原数组编号arr[i-1])放入arr[2i-2]
bi(原数组编号arr[n+i-1])放入arr[2i-1]
这样就需要分两类来讨论~有没有更简单的方法呢~我们不妨先来试试看~(以下不再使用ai、bi只写arr中的编号)
原数组:0,1,2,……n-1,n,n+1,n+2,……2n-1
新数组:0, ,2, ,4……,2n-2
原数组中的0,1,2……n-1分别对应新数组中的0,2,4……2n-2
原数组中的n,n+1,n+2,……2n-1还没有完成对应,而新数组中的1,3,5,……,2n-1位置也空着等待填充
如果让没对应的部分继续按照之前的规则对应(i对应2i)会是什么样子的呢。
原数组:(0,1,2,……n-1,)(n,n+1,n+2,……2n-1)
新数组:(0, ,2, ,4……, 2n-2) (2n,2n+2,2n+4,……, 4n-2)
为了便于观察我把a、b用括号分别括起来了~
这么看起来我们似乎把数组扩大了一倍~但是数组相邻元素间存在着间隔而且恰好还能再存入一个元素~我们只需要把后面的b组数据全部提前一定距离(2n-1)就能恰好插入a组数据的空位了
a组(0, ,2, ,4……, 2n-2)
b组 (1, ,3, ,5……, 2n+1)
合并之后刚好是我们需要的结果:1,2,3,4,5……2n-2,2n-1
总的来说只需要把i放入2i mod(2n-1)即可~
不妨设原编号为x,新遍号为y,y=2*x mod (2n-1)~
现在要求x,
y为奇数时表示商1,y=2x-(2n-1),x=(y+(2n-1))/2
y为偶数时表示商0,y=2x,x=y/2
综上:x=(y+y%2(2n-1))/2
在eclipse下编程测试了下发现个小问题明天再来修改~数组长度取10的时候arr[3]和arr[6]不会被遍历到,因为它们互相调用,而我的算法是x=(y+y%2(2n-1))/2;arr[y] = arr[x];y = x;循环再找下一个被替换掉的位置~(为了节省空间避免挤掉还未被移走的数据~)
PS:文章中充满了“~”,这个只是个人语癖~和按位取反运算符无关~
以下是源代码: