前言:
相信大家在学习数据结构时,都会接触到线性表吧,在多数情况下,线性表可以简单的用数组实现,但事情也总不会一直那么简单,对于此,在这里我们就引进了链表,其在解决一些相对复杂问题就比线性表十分好用,本篇博客将介绍链表,并用它和数组进行比较。
1.1.初步分析:
1.1.1.题目:
1.1.2.分析:
- 可知,该题要根据指令来移动指定元素,在保证其它元素不动的情况下,我们只移动指定元素,最后组成一个新的数组。
- 这是一道可以用链表的方法去解决,结合数组知识,我们以指令A 1 4为例(在这里我们以1位首元素位置),将位置为1的元素先移动到2的右边,此时2元素的位置变为1,以此类推,移动到4的左边(相邻)。
- 当执行B 3 5 指令时,和上述执行A 1 4指令一样的方法进行移动,然而,这里有个不同点,就是要跨过元素位置为5的元素,我们可以将位置为3的元素代替元素位置为5的元素,其位置为5的元素其位置变为4.
- 当然,上述是在调用元素的位置,所以,我们还需要一个可以查找元素位置的函数,最后对上面进行整合即可完成。
1.1.3.代码:
#include<stdio.h>
const int N=1000;
int main(){
int C[N],m,n;
void shift_circular_left(int a,int b,int n,int C[]); //该函数将位置为a的元素移动到b位置元素的左边
void shift_circular_right(int a,int b,int n,int C[]); //该函数将位置为a的元素移动到b位置元素的右边
int find(int a,int n,int C[]); //找到元素a的位置
while(scanf("%d",&n)==1&&scanf("%d",&m)==1){ //n为求得个数,m为指令个数
int i,c,d;
char k;
for(i=1;i<=n;i++){
C[i]=i;
}
for(i=1;i<=m;i++){
scanf("%s%d%d",&k,&c,&d); //c,d表示元素
int c1=find(c,n,C); //找到元素的位置
int d1=find(d,n,C);
if(k=='A'){ //下面代码大家可以在数轴上描写即可理解
if(c1<d1){
shift_circular_left(c1,d1,n,C);
}
else{
shift_circular_right(d1,c1,n,C);
}
}
else{
if(c1<d1){
shift_circular_left(c1,d1+1,n,C);
}
else{
shift_circular_right(d1+1,c1,n,C);
}
}
printf("\n");
}
}
}
void shift_circular_left(int a,int b,int n,int C[]){ //将位置为a的元素移动到元素位置为b的左边
int B[N],i,j=1,k,l;
for(i=1;i<a;i++){
B[j++]=C[i];
}
l=j;
for(i=a+1;i<=b-1;i++){
B[l++]=C[i];
}
k=l-1;
B[k+1]=C[a];
for(i=b;i<=n;i++){
B[k+2]=C[i];
k++;
}
for(i=1;i<=n;i++){
printf("%d ",B[i]);
}
return ;
}
void shift_circular_right(int a,int b,int n,int C[]){ //将位置为b的元素移动到位置为a元素的右边
int B[N],i,j=1,k,l,m;
for(i=1;i<a;i++){
B[j++]=C[i];
}
k=j-1;
B[k+1]=C[b];
l=k+2;
for(i=a;i<b;i++){
B[l++]=C[i];
}
m=l;
for(i=b+1;i<=n;i++){
B[m++]=C[i];
}
for(i=1;i<=n;i++){
printf("%d ",B[i]);
}
return ;
}
int find(int a,int n,int C[]){ //定义查找元素位置函数
int i=1,k;
while(i<=n){
if(C[i]!=a){
i++;
}
else{
k=i;
break;
}
}
return k;
}
大家你知道吗当我在发布这段代码时,我就在想,当你们在看这段代码时会不会在心里狠狠的骂我😄😄😄。好了,但我还是要忍受你们的骂意,继续完成下面的内容😃.
如果大家复制上面代码时去执行的话,你会发现其耗费的时间是有点长的,但是上面代码思路简单,易容易理解哈。还有你们要注意,上面scanf("%s%d%d",&k,&c,&d);为什么是用%s而不是%c?其实,当用scanf("%d")读取整数时,并没有读取后面的回车换行符,这是用%c会读到这个回车换行符,而只有%s才会跳过它,读取下一个非空白符组成的字符串。
经过小编的思考及相关资料的启发,我用了另一方法去完成上述问题,如下:
1.1.3.深入分析:
- 我们可以将要移动的元素移出,然后再插入,即可。
- 比如一指令A 1 4为例,我们可以将位置为1的元素先移出原数组,然后在插入到位置为4的元素的左边,当然对于指令为B 3 5是同样的方法。
1.1.4.代码:
#include<stdio.h>
const int M=1000;
int main(){
int C[M],n,m;
void link_left_right1(int a,int b,int n,int C[]); //定义一个移动数组元素的函数
void link_left_right2(int a,int b,int n,int C[]);
int find(int a,int n,int C[]); //一个查找数组的位置的函数
while(scanf("%d",&n)==1&&scanf("%d",&m)==1){ //自行分析下面代码的作用
for(int i=1;i<=n;i++){
C[i]=i;
}
int x,y;
char type;
for(int j=1;j<=m;j++){
scanf("%s%d%d",&type,&x,&y);
int x1=find(x,n,C);
int y1=find(y,n,C);
if(type=='A'){
if(x1<y1){
link_left_right1(x1,y1,n,C); //将y1位置的元素移到x1位置元素的左边
}
else{
link_left_right2(y1,x1,n,C); //将x1位置的元素移动到y1位置元素的左边
}
}
else{
if(x1<y1){
link_left_right1(x1,y1+1,n,C);
}
else{
link_left_right2(y1+1,x1,n,C);
}
}
printf("\n");
}
}
}
void link_left_right1(int a,int b,int n,int C[]){
int i,B[M],j=1,k,A[M];
for(i=1;i<a;i++){
B[j++]=C[i];
}
for(i=a+1;i<=n;i++){
B[j++]=C[i];
}
for(j=1;j<b-1;j++){
A[j]=B[j];
}
A[b-1]=C[a];
for(j=b-1;j<=n-1;j++){
A[j+1]=B[j];
}
for(i=1;i<=n;i++){
printf("%d ",A[i]);
}
return ;
}
void link_left_right2(int a,int b,int n,int C[]){
int i,B[M],j=1,k,A[M];
for(i=1;i<b;i++){
B[j++]=C[i];
}
for(i=b+1;i<=n;i++){
B[j++]=C[i];
}
for(j=1;j<a;j++){
A[j]=B[j];
}
A[a]=C[b];
for(i=a;i<=n-1;i++){
A[i+1]=B[i];
}
for(i=1;i<=n;i++){
printf("%d",A[i]);
}
return ;
}
int find(int a,int n,int C[]){ //定义查找数组位置的函数
int i=1,k;
while(i<=n){
if(C[i]!=a){
i++;
}
else{
k=i;
break;
}
}
return k;
}
1.1.5.上述代码的对比:
从算法的复杂度来看我们很容易发现,第二段代码相对较好,其算法复杂度及时间复杂度都比第一段代码要优,换句话说就是效率更高。
2.1.对比测试:
不知道读者有没有发现题目明确说过m和n的值最大会达到什么地步,而我给出的两段代码都不会达到那种地步,然而,在这里,我们可以建立一个数据生成器,来对大量数据进行测试。
2.1.1.代码:
//测试实例
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int n=100,m=100000;
double random(){
return (double)rand()/RAND_MAX; //生成[0,1]的随机数,下面会详细解析RAND_MAX
}
double random(int m){
return (int)(random()*(m-1)+0.5); //随机生成[0,m-1]的随机数
}
int main(){
srand(time(NULL)); //保证每次循环后生成的随机数不是相同的
printf("%d %d",n,m);
for(int i=0;i<m;i++){
if(rand()%2==0){ //间断的输出A和B
printf("A ");
}
else{
printf("B ");
}
int X,Y;
for(;;){
X=random(n)+1; //随机生成[0,n]的随机数
Y=random(n)+1;
if(X!=Y){ //只有X,Y不相等才是合法的
break;
}
}
printf("%d %d\n",X,Y);
}
return 0;
}
对于RAND_MAX,其在C中的值至少为32767,而当rand()/RAND_MAX,表示,生成的随机数位于[0,1]内。
当然啦,头文件include<stdlib.h>是调用rand()需要的头文件,其include<time.h>是调用srand()需要的头文件,其中注意的是,当你在用srand()时,要声明srand(time(NULL));,否则,会出错。当你不调用srand(time(NULL));时,则每次生成的随机会和上一次生成的随机数是相同的,只有调用srand(time(NULL));时,每次生成的随机数会随时间的变化,而生成不同的随机数。
最后,希望大家多多支持哦!一起加油,一起进步!!!😄
3.1.参考文献:
《算法竞赛入门》 作者:刘汝佳