数组元素左移的解法

来源:互联网 发布:拉丁美洲独立运动知乎 编辑:程序博客网 时间:2024/06/08 11:18

题目:对于一维数组A[0...n-1](n>1),设计在时间和空间上方面尽可能有效率的算法,将A中的序列循环左移P(0<p<n)个位置,即将A中的数据从(A0,A1,A2......An-1)转变成(Ap,Ap+1......An-1,A0,A1......Ap-1),并分析所设计算法的时间复杂度和空间复杂度

其实我想大家在看到这道题时,很希望能使用链表来做。因为这样只需把其看成一个队列,队头移出,队尾移进,不浪费额外的空间且时间复杂度为线性阶;甚至熟悉指针的同学更能想到把原链表的尾指针指向首元结点,第p个结点的指针指向null,而头指针指向第p+1个结点,这样,只需简单的操作且时间复杂度为常数阶,可以不费吹灰之力解决问题。不过,题目硬性要求要使用一维数组,所以难度上就加大了。

原始链表


移位后链表


接下来是四种解决方法

C语言实现

算法1

创造一个额外数组,用来存取移位的数据
#include<stdio.h>
int main()
{
int arr[10]={0,1,2,3,4,5,6,7,8,9};
int s[10];
int p;
scanf("%d", &p);
for(int i=0; i<p; i++)
s[i]=arr[i];
for(int i=p; i<10; i++)
arr[i-p]=arr[i];
for(int i=9,j=p; i>9-p; i--)
arr[i]=s[--j];
for(int i=0; i<10; i++)
printf("%3d", arr[i]);
return 0;
}
时间复杂度O(n),缺点:牺牲空间。


算法2

循环p次,每次把最前面的数移到最后面
#include<stdio.h>
int main()
{
int arr[10]={0,1,2,3,4,5,6,7,8,9};
int p;
scanf("%d", &p);
for(int i=0; i<p; i++){
int temp=arr[0];
for(int j=1; j<10; j++)
arr[j-1]=arr[j];
arr[9]=temp;
}
for(int i=0; i<10; i++)
printf("%3d", arr[i]);
return 0;
}
时间复杂度:O(n^2),缺点:牺牲时间

前两种方法都不是特别好,随着时间的减少,空间的利用会增大。

其实很多时候,时间和空间都是此消彼长的。


算法3

先全反序,再以9-p与10-p为界限,分别对前后进行反序
#include<stdio.h>
int main()
{
int arr[10]={0,1,2,3,4,5,6,7,8,9};
int p;
scanf("%d", &p);
for(int i=0; i<5; i++){
int temp=arr[i];
arr[i]=arr[9-i];
arr[9-i]=temp;
}
for(int i=0; i<(10-p)/2; i++){
int temp=arr[i];
arr[i]=arr[9-p-i];
arr[9-p-i]=temp;
}
for(int i=0; i<p/2; i++){
int temp=arr[9-i];
arr[9-i]=arr[10-i-p];
arr[10-p-i]=temp;
}
for(int i=0; i<10; i++)
printf("%3d", arr[i]);
return 0;
}
时间复杂度:O(n)

算法4

以p为间隔,分别往前移位,第一个数则移到最后相应的位置
#include<stdio.h>
int main()
{
int arr[10]={0,1,2,3,4,5,6,7,8,9};
int p;
scanf("%d", &p);
for(int i=0; i<p; i++){
int temp=arr[i];
int pos=i;
while(pos<10){
arr[pos]=arr[pos+p];
pos+=p;
}
arr[pos-p]=temp;
}
for(int i=9; i>9-10%p; i--){
int temp=arr[9];
for(int j=8; j>9-p; j--)
arr[j+1]=arr[j];
arr[10-p]=temp;
}
for(int i=0; i<10; i++)
printf("%3d", arr[i]);
return 0;
}
时间复杂度:O(n^2),这个方法我起初也想到过,不过觉得不太可行就没去尝试,今天上午上课听到老师说到这个方法,就去尝试了一下,老师举的例子是12个数移位是3,的确是看似简单。不过我发现其中是有原因的,因为12能整除3,所以每次移位都能恰好。而假设10个数移位3,就不能刚刚好了,所以,需要对最后面的数进行额外的处理,我发现,需要把后面的数进行向右移位余数个位数,只有这样,才能成功移位。而且即使这样,时间复杂度也为n^2,时间上牺牲太多,故不太建议。

综上,建议使用算法3

阅读全文
0 0