正常思维:使用return 语句,但每调用一次函数 return 语句只能返回一个值 。这是C语言语法规则。
该怎么实现一个函数返回两个值或是多个值?,可以采用“间接方法”。大概有三种方法:全局变量法、变量指针法、结构体指针法等。
1. 全局变量法
全局变量法,顾名思义,将需要的变量X设为全局变量 ,在调用应用函数后,X 被附上值 ,可以直接使用X变量值。
代码分析:(编程之美 小飞 电梯调度算法)
// 全局变量法 :返回多个值
//但毕竟全局变量应用过程中有很多危险,要慎重使用。
#include
/* 问题描述*/
/**
* 编程之美 小飞 电梯调度算法
* 在繁忙的时间,每次电梯从一层往上走时,我们只允许电梯停在其中的某一层。
* 所有乘客都从一楼上电梯,到达某层楼后,电梯听下来,所有乘客再从这里爬楼梯到自己的目的层。
* 在一楼时,每个乘客选择自己的目的层,电梯则自动计算出应停的楼层。
* 问:电梯停在哪一层楼,能够保证这次乘坐电梯的所有乘客爬楼梯的层数之和最少?
思路:当电梯停靠在第i层时,乘客所要爬的总的楼梯数为Y.
假设有N1个乘客要到达的层数i.
所以有:
(1)当电梯改停在i-1,则 Y+(N2+N3-N1)
(2)当电梯改停在i+1,则 Y+(N1+N2-N3)
所以当后面那部分的值<0时(如(2)的N1+N2
因此,我们可以从第一层开始,用以上策略,考察N1,N2,N3的值,依次调整以得到最优解.
*/
int targartfloor;
int sumstars;
void getMinFloors(int N ,int * nperson)
{
//int nperson[i] // 到达i层下的总人数
//int targartfloor;
//int sumstars;
int N1; // 到达i层以下 楼层总人数
int N2; //到达i层 楼层总人数
int N3; //到达i层以上 楼层总人数
//初始化
// 从第二层开始 计算N1 N2 N3
targartfloor=2; //
N1=0;
N2=nperson[2]; // 第二层
N3=0;
int i ,j;
for(i=3;i<=N;i++)
{
N3+=nperson[i];
sumstars+=nperson[i]*(i-targartfloor);
}
//让电梯依次改停在3楼、4楼...N楼,出现更优解时,则调整电梯停靠层数以及N1,N2,N3
for(i=3;i<=N;i++)
{
if(N1+N2
{
targartfloor=i;
sumstars+=N1+N2-N3;
// 为下次判断 修正N1 N2 N3
N1 +=N2;
N2=nperson[i];
N3-=nperson[i];
}
else
break;
}
}
int main()
{
int nperson[50]={0,0,2,5,7,8,9,6,6,1,4,4,8,5,2,4,5,8,6,3,3,5,9,9,6,6,9,8,8,5,5,9,6,6,3} ;
//int nperson[50]={0,0,2,5,7,8,9,6,} ;
int N=34;
int i;
for(i=2;i<=N;i++)
{
printf("在第%d层下的乘客人数为:%d\n",i,nperson[i]);
}
printf("************************************\n");
getMinFloors(N,nperson);
printf("电梯停在第%d层,所有的乘客所需爬楼层数最少,最少为:%d层",targartfloor,sumstars);
return 0;
}
设置全局变量targartfloor ,sumstats ,调用 getMinfloors函数后 ,在主函数中直接得有需要的targartfloor ,sumstats 的值。
但毕竟全局变量应用过程中有很多危险,要慎重使用。全局变量维护起来麻烦,因为全局变量可能在多个地方被修改。在查错是也不好发现问题。
2.变量指针法(数组指针法)
C语言函数参数的传递方式有值传递与地址传递。当进行值传递时,主调函数把实参的值复制给形参,形参获得从主调函数传递过来的值运行函数。在值传递过程中被调函数参数值的更改不能导致实参值的更改。
而如果是地址传递,由于传递过程中从实参传递过来的是地址,所以被调函数中形参值的更改会直接导致实参值的更改。可以把变量的地址作为函数的形式参数,函数被调用后,形参元素改变导致实参改变,我们再从改变后的实参数组元素中获得函数的多个返回值。
(如果所求的返回值类型相同,我们可以考虑把多个返回值作为数组元素定义成一个数组的形式,并使该数组的地址作为函数的形式参数,以传址方式传递数组参数。函数被调用后,形参数组元素改变导致实参改变,我们再从改变后的实参数组元素中获得函数的多个返回值。)
代码分析:(编程之美 小飞 电梯调度算法)
#include
/* 问题描述*/
/**
* 编程之美 小飞 电梯调度算法
* 在繁忙的时间,每次电梯从一层往上走时,我们只允许电梯停在其中的某一层。
* 所有乘客都从一楼上电梯,到达某层楼后,电梯听下来,所有乘客再从这里爬楼梯到自己的目的层。
* 在一楼时,每个乘客选择自己的目的层,电梯则自动计算出应停的楼层。
* 问:电梯停在哪一层楼,能够保证这次乘坐电梯的所有乘客爬楼梯的层数之和最少?
思路:当电梯停靠在第i层时,乘客所要爬的总的楼梯数为Y.
假设有N1个乘客要到达的层数i.
所以有:
(1)当电梯改停在i-1,则 Y+(N2+N3-N1)
(2)当电梯改停在i+1,则 Y+(N1+N2-N3)
所以当后面那部分的值<0时(如(2)的N1+N2
因此,我们可以从第一层开始,用以上策略,考察N1,N2,N3的值,依次调整以得到最优解.
*/
void getMinFloors(int N ,int * nperson ,int *targartfloor,int *sumstars)
{
//int nperson[i] // 到达i层下的总人数
//int targartfloor;
//int sumstars;
int N1; // 到达i层以下 楼层总人数
int N2; //到达i层 楼层总人数
int N3; //到达i层以上 楼层总人数
//初始化
// 从第二层开始 计算N1 N2 N3
*targartfloor=2; //
N1=0;
N2=nperson[2]; // 第二层
N3=0;
*sumstars=0;
int i ;
for(i=3;i<=N;i++)
{
N3+=nperson[i];
(*sumstars)+=nperson[i]*(i-2);
}
//让电梯依次改停在3楼、4楼...N楼,出现更优解时,则调整电梯停靠层数以及N1,N2,N3
i=0;
for(i=3;i<=N;i++)
{
if(N1+N2
{
*targartfloor=i;
(*sumstars)+=N1+N2-N3;
// 为下次判断 修正N1 N2 N3
N1 +=N2;
N2=nperson[i];
N3-=nperson[i];
}
else
break;
}
}
int main()
{
int nperson[50]={0,0,2,5,7,8,9,6,6,1,4,4,8,5,2,4,5,8,6,3,3,5,9,9,6,6,9,8,8,5,5,9,6,6,3} ;
//int nperson[50]={0,0,2,5,7,8,9,6,} ;
int targartfloor;
int sumstars;
int N=34;
int i;
for(i=2;i<=N;i++)
{
printf("在第%d层下的乘客人数为:%d\n",i,nperson[i]);
}
printf("************************************\n");
getMinFloors(N,nperson,&targartfloor,&sumstars);
printf("电梯停在第%d层,所有的乘客所需爬楼层数最少,最少为:%d层\n",targartfloor,sumstars);
return 0;
}
传递变量地址&targartfloor &sumstats 调用函数后 形参元素改变导致实参改变. 变量targartfloor sumstars 中包含所需的值。
值得注意的是 传入变量初始化问题。
另:数组指针传递 可以把 两变量写进数组A ,A[]={targartfloor,sumstars}, 此时函数变为 void getMinfloor(int N ,int *nperson, int A函数内用 A[0] A[1] 代替变量targartfloor,sumstars 参与运算。调用函数: int B[2]={};getMinfloor(int N ,int *nperson, B),求得B[0] B[1]中包含所需的值。
3.结构体指针传递法
我们知道如果返回的数个数值的数据类型不一致,可以考虑把要求返回的数个值定义成一个结构体,然后同样以传递结构体指针方式把结构体的指针传递给形参结构体指针,那么函数中对形参结构体的修改即是对实参结构体的修改,函数被调用后获取的实参结构体成员即为函数的多个返回值。
// 测试返回多个值 ------结构体法:试用 返回不同类型的数据
//传递结构体指针
#include
/* 问题描述*/
/**
* 编程之美 小飞 电梯调度算法
* 在繁忙的时间,每次电梯从一层往上走时,我们只允许电梯停在其中的某一层。
* 所有乘客都从一楼上电梯,到达某层楼后,电梯听下来,所有乘客再从这里爬楼梯到自己的目的层。
* 在一楼时,每个乘客选择自己的目的层,电梯则自动计算出应停的楼层。
* 问:电梯停在哪一层楼,能够保证这次乘坐电梯的所有乘客爬楼梯的层数之和最少?
思路:当电梯停靠在第i层时,乘客所要爬的总的楼梯数为Y.
假设有N1个乘客要到达的层数i.
所以有:
(1)当电梯改停在i-1,则 Y+(N2+N3-N1)
(2)当电梯改停在i+1,则 Y+(N1+N2-N3)
所以当后面那部分的值<0时(如(2)的N1+N2
因此,我们可以从第一层开始,用以上策略,考察N1,N2,N3的值,依次调整以得到最优解.
*/
struct minfloor
{
int targartfloor;
int sumstars;
};
void getMinFloors(int N ,int * nperson, struct minfloor *mf)
{
//int nperson[i] // 到达i层下的总人数
//int targartfloor;
//int sumstars;
int N1; // 到达i层以下 楼层总人数
int N2; //到达i层 楼层总人数
int N3; //到达i层以上 楼层总人数
//初始化
// 从第二层开始 计算N1 N2 N3
mf->targartfloor=2; //
N1=0;
N2=nperson[2]; // 第二层
N3=0;
int i ,j;
for(i=3;i<=N;i++)
{
N3+=nperson[i];
mf->sumstars+=nperson[i]*(i-mf->targartfloor);
}
//让电梯依次改停在3楼、4楼...N楼,出现更优解时,则调整电梯停靠层数以及N1,N2,N3
for(i=3;i<=N;i++)
{
if(N1+N2
{
mf->targartfloor=i;
mf->sumstars+=N1+N2-N3;
// 为下次判断 修正N1 N2 N3
N1 +=N2;
N2=nperson[i];
N3-=nperson[i];
}
else
break;
}
}
int main()
{
int nperson[50]={0,0,2,5,7,8,9,6,6,1,4,4,8,5,2,4,5,8,6,3,3,5,9,9,6,6,9,8,8,5,5,9,6,6,3} ;
//int nperson[50]={0,0,2,5,7,8,9,6,} ;
int N=34;
int i;
struct minfloor pr;
for(i=2;i<=N;i++)
{
printf("在第%d层下的乘客人数为:%d\n",i,nperson[i]);
}
printf("************************************\n");
getMinFloors(N,nperson,&pr);
printf("电梯停在第%d层,所有的乘客所需爬楼层数最少,最少为:%d层",pr.targartfloor,pr.sumstars);
return 0;
}
原理同方法2 类似。
三种方法 都得到同一结果:
小结: 复习小飞 电梯调度算法(动态规划法)时,引申出C语言的一个基本问题:一个函数如何返回两个值或多个值?
建议使用方法:变量指针法 或是结构体指针法。