关于二级c中经常出现的数组排列算法的个人理解(y[j++]=x[i];x[i]=-1;)

关于二级c中经常出现的数组排列算法的个人理解

最近一直在复习c语言刷题准备考试,其中有一道程序题感觉很有意思,有些地方不是很明白,于是上网搜了一下也没有人说出些所以然来,自己研究了一下觉得对考试很有用,所以写在这里。
先看下代码:

#include  <stdlib.h>
#include  <stdio.h>
#define   N   10
double fun(double  *x)
{
    
     int  i, j;    double  s, av, y[N];
  s=0;
  for(i=0; i<N; i++)  s=s+x[i];
/**********found**********/
  av=__1__;
  for(i=j=0; i<N; i++)
    if( x[i]>av ){
    
    
/**********found**********/
      y[__2__]=x[i];
	  x[i]=-1;}
  for(i=0; i<N; i++)
/**********found**********/
    if( x[i]!= __3__) y[j++]=x[i];
  for(i=0; i<N; i++)x[i] = y[i];
  return  av;
}
void main()
{
    
     int  i;     double  x[N];
  for(i=0; i<N; i++){
    
     x[i]=rand()%50; printf("%4.0f ",x[i]);}
  printf("\n");
  printf("\nThe average is: %f\n",fun(x));
  printf("\nThe result :\n",fun(x));
  for(i=0; i<N; i++)  printf("%5.0f ",x[i]);
  printf("\n");
}

在此程序中,函数fun的功能是:计算形参x所指数组中N个数的平均值(规定所有数均为正数),将所指数组中大于平均值的数据移动到数组的前部,小于或者等于平均值的数据移动到数组的后部,平均值作为函数返回,在主函数中输出平均值和移动后的数据。
首先给的是一个double类型的函数,利用函数对给定的数组进行排列,作为初学者在第一句在给函数定义的时候很容易就想到这样定义形参:

double fun(double  x[])

而习题里给出的是:

double fun(double  *x)

使用指针作为形参传递数组,在翻阅了几篇文章之后仍然不是很明白,但是大概知道了是这样一个原理:
形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。通俗来说就是,指针存放的是数的地址,而数组名存放的是该数组的首地址。所以可以应用指针的方法对数组进行传递。
但是在经过修改之后,我使用double x[] 进行定义,返回的实参仍然是被改变的,这一点希望高人指点一二。当然这部分不是这个考题的重点,首先在该函数内定义了几个变量,对了还有开头的宏定义,先是对传进来的参数求解平均值,很容易就想到了两种方法:
第一种就是av=(x[1]+x[2]+...+x[N])/N的方法,另一种就是av=x[1]/N+x[2]/N+...x[N]/N,也就是这样:

for(i=av=0;i<N;i++)av+=x[i]/N;

那么考题给的就是第一种方法,先通过for循环对x进行累加,然后除以N,所以第一个空填s/N。
在一开始定义的时候给出了一个double类型的数组y[N],那么接下来就要用y[N]辅助x[]进行排列,首先通过for循环对传进来的x[]数组进行第一次的遍历,筛选出大于均值的数,也就是这段代码:

for(i=j=0; i<N; i++)
    if( x[i]>av ){
    
    
/**********found**********/
      y[__2__]=x[i];
	  x[i]=-1;}

将i,j置0,进行N次循环,如果x[]数组中的某个数大于均值后,y[_2_]=x[i];这是第二个空。先假如x的第0个元素就是大于均值的,那么空中填的数要反映出第一次循环,那么i或者j都反映了循环,如果接下来的空都是大于均值的那么这个空填i足够实现的,但是后边如果有小于均值的呢,假如x数组第二个元素小于均值,那么if循环条件不足,i++,假如x元素的第三元素大于均值,那么现在i=2,假如填y[i]=x[i] 的话,那么y的第三个元素等于x的第三个元素,那么y的第二个元素就会是空的,所以这个空填i不行。
那么填j呢,根据上面的思维,假如x的第一个元素大于均值,第二个元素小于均值,此时没有问题,当x的第三个元素大于均值时呢,此时j=0,就会将x的第三个元素传给y的第j个元素,也就是y的第0个元素,这样就把上一个传进y中的大于均值的数覆盖了。所以第二个空应该为j++,在给y传进一个元素之后y进行自加。
至于为什么要x[i]=-1;就好理解了,就是将在第一次遍历x数组时,将x数组中大于均值的元素都替换成-1 ,这样为接下的第二次遍历提供了方便。其实替换成哪个负数都可以,这只是一个标志。

 for(i=0; i<N; i++)
/**********found**********/
    if( x[i]!= __3__) y[j++]=x[i];
  for(i=0; i<N; i++)x[i] = y[i];
  return  av;

这段代码就是对x数组进行第二次的遍历,找出小于均值的数,根据上一次遍历我们知道,x中大于均值的数都传递给了y数组,并且x中之前大于均值的数都替换成了-1,所以接下来的遍历就是要找出x数组中不等于-1 的数,让它从x数组传到y数组,所以第三个空就应该填写-1
然后通过for循环的方式将y数组再传递给x数组,return av均值。

那么在主函数中,利用for循环结合rand()%50寻找出小于50的随机数赋值给x[N],

void main()
{
    
     int  i;     double  x[N];
  for(i=0; i<N; i++){
    
     x[i]=rand()%50; printf("%4.0f ",x[i]);}
  printf("\n");
  printf("\nThe average is: %f\n",fun(x));
  printf("\nThe result :\n",fun(x));
  for(i=0; i<N; i++)  printf("%5.0f ",x[i]);
  printf("\n");
}

接下来就是调用函数,再打印出来。

猜你喜欢

转载自blog.csdn.net/weixin_50060428/article/details/114451521