基于C中不均匀范围的计算量
calculating amount based on uneven ranges in C
我在翻之前的纸质题时发现有一道题要求我根据每个客户消耗的单位(电力)数量出具账单。给出了 table 指示如何完成计算。我已经使用 if else 语句以非常基本的方式制作了程序。我想知道是否有比使用 if else 更好的方法。也许循环?我尝试使用循环,但它对我来说不切实际,因为范围不是恒定的。
这是该问题的一部分的屏幕截图。Question Screenshot
我创建的用于计算的函数如下所示。
void findBill(int table[],float ar[],int size)
{
int i;
float bill;
for(i=0; i<7 ; i++)
{
if((table[i]>=0)&&(table[i]<=5))
{ bill=table[i]*3.0;
}
else if((table[i]>=6)&&(table[i]<=10))
{ bill=5*3.0+(table[i]-5)*7.0;
}
else if((table[i]>=11)&&(table[i]<=15))
{ bill=5*3.0+5*7.0+(table[i]-10)*15.0;
}
else if((table[i]>=16)&&(table[i]<=20))
{ bill=5*3.0+5*7.0+5*15.0+(table[i]-15)*30.0;
}
else if((table[i]>=21)&&(table[i]<=25))
{ bill=5*3.0+5*7.0+5*15.0+5*30.0+(table[i]-20)*50.0;
}
else if((table[i]>=26)&&(table[i]<=30))
{ bill=5*3.0+5*7.0+5*15.0+5*30.0+5*50.0+(table[i]-25)*75.0;
}
else if((table[i]>=31)&&(table[i]<=40))
{ bill=5*3.0+5*7.0+5*15.0+5*30.0+5*50.0+5*75.0+(table[i]-30)*90.0;
}
else if((table[i]>=41)&&(table[i]<=50))
{ bill=5*3.0+5*7.0+5*15.0+5*30.0+5*50.0+5*75.0+10*90.0+(table[i]-40)*105.0;
}
else if((table[i]>=51)&&(table[i]<=75))
{ bill=5*3.0+5*7.0+5*15.0+5*30.0+5*50.0+5*75.0+10*90.0+10*105.0+(table[i]-50)*110.0;
}
else if(table[i]>75)
{ bill=5*3.0+5*7.0+5*15.0+5*30.0+5*50.0+5*75.0+10*90.0+10*105.0+25*110.0+(table[i]-75)*120.0;
}
ar[i]=bill;
}
}
尽管这有效,但我觉得这是糟糕的编码,如果有 100 个范围会怎样。请建议我另一种更简单的方法来执行此操作,而不是编写简单的 if else 语句。
P.S : 我是初学者,所以请用 C 中的 stdio.h 建议答案。
提前致谢。
你在想这样的事情吗?代码相当简单易懂。如有需要,请随时提出问题。
#include <limits.h> // MAX_INT
#define MIN(a, b) {((a) < (b)) ? (a) : (b);
typedef struct RATE_DEF
{
float slice; // ceiling for this rate - ceiling fro previous rate
float ppu; // price per unit
};
const struct RATE_DEF RATE_TABLE[] =
{
{ 5, 3.f },
{ 5, 7.f },
/* ... */
{ MAX_INT, 120.f }, // much better
};
#define NUM_RATES (sizeof(RATE_TABLE) / sizeof(RATE_TABLE[0]))
void findBill(int table[],float ar[],int size)
{
int i, j, amt, slice;
float bill;
for(i=0; i<7 ; i++)
{
amt = table[i];
bill = 0.f;
for (j = 0; amt > 0 && j < NUM_RATES; ++j)
{
slice = MIN(amnt, RATE_TABLE[j].slice);
bill += (slice * RATE_TABLE[j].ppu);
amt -= slice;
}
ar[i] = bill;
}
[编辑] 有几个错别字,但我今天很懒:)
我编写了一个小程序,它比您当前的示例更具可扩展性。它使用循环,因此它具有 O(n) 时间和 space 复杂性,而您的程序对两者都有恒定的复杂性。尽管如此,我的代码会计算填充任何值的任何大小范围的值。此代码确实需要您在范围内进行实际硬编码,但这相对容易摆脱。
int calcBill(int input){
int total = 0;
int billCost[] = {3,7,15,30,50,75,90,105,110,120};
int billRange[] = {5,10,15,20,25,30,40,50,75,200};
int rangeAdd[10];
int sizeOfRange = sizeof(billCost)/sizeof(int);
//add up the first section
int i = 0;
for(; i<sizeOfRange; i++){
if(i == 0)
rangeAdd[i] = billCost[i] * billRange[i];
else {
rangeAdd[i] = billCost[i] * (billRange[i] - billRange[i-1]);
rangeAdd[i] += rangeAdd[i-1];
}
}
i = 0;
for(; i<sizeOfRange; i++){
if(billRange[i] > input)
break;
}
if(i == 0){
total = input * billCost[0];
}
else {
total += (input - billRange[i-1]) * billCost[i];
if(i > 0)
total += rangeAdd[i-1];
}
printf("%d %d\n", input, total);
return total;
}
此代码使用两个数组(billCost 和 billRange)来计算当您使用给定范围内的所有单位时每张账单的费用。例如,25 个单位的账单存储在 rangeAdd 数组中的索引 4 处,30 个单位的账单存储在索引 5 处。这很容易计算,只需遍历两个数组即可。然后代码找到两个数组的单位所处的最大范围的索引(对于 36 的输入,这将是范围 31-40,或索引 7)。该代码计算该范围内的单位数,并将该范围内的总账单(单位数 * 价格)添加到范围内预先计算的值中,并为其正下方的索引添加值。
显然,如果您 运行 执行此程序数百次,则每次都会重新计算此函数中的 rangeAdd 数组。您可以预先计算它并将其作为变量传递给函数。这只是一个概念证明,可以提高效率。
由于根据单位数量计算成本没有固定模式,因此很难避免值的硬编码数组。
但我认为您所做的实施可以更简洁。
我认为比较好的做法是下面的
void findBill(int table[], float arr[], int size) {
int levels[]={75,50,40,30,25,20,15,10,5,0};
float costs[]={120,110,105,90,75,50,30,15,7,3};
int level_cnt=sizeof(levels) / sizeof(int);
for(int i=0;i<size;i++) {
arr[i]=0;
for(int c=0;c<level_cnt;c++) {
if(table[i]>levels[c]) {
arr[i]+=(table[i]-levels[c])*costs[c];
table[i]=levels[c];
}
}
}
}
我在翻之前的纸质题时发现有一道题要求我根据每个客户消耗的单位(电力)数量出具账单。给出了 table 指示如何完成计算。我已经使用 if else 语句以非常基本的方式制作了程序。我想知道是否有比使用 if else 更好的方法。也许循环?我尝试使用循环,但它对我来说不切实际,因为范围不是恒定的。 这是该问题的一部分的屏幕截图。Question Screenshot
我创建的用于计算的函数如下所示。
void findBill(int table[],float ar[],int size)
{
int i;
float bill;
for(i=0; i<7 ; i++)
{
if((table[i]>=0)&&(table[i]<=5))
{ bill=table[i]*3.0;
}
else if((table[i]>=6)&&(table[i]<=10))
{ bill=5*3.0+(table[i]-5)*7.0;
}
else if((table[i]>=11)&&(table[i]<=15))
{ bill=5*3.0+5*7.0+(table[i]-10)*15.0;
}
else if((table[i]>=16)&&(table[i]<=20))
{ bill=5*3.0+5*7.0+5*15.0+(table[i]-15)*30.0;
}
else if((table[i]>=21)&&(table[i]<=25))
{ bill=5*3.0+5*7.0+5*15.0+5*30.0+(table[i]-20)*50.0;
}
else if((table[i]>=26)&&(table[i]<=30))
{ bill=5*3.0+5*7.0+5*15.0+5*30.0+5*50.0+(table[i]-25)*75.0;
}
else if((table[i]>=31)&&(table[i]<=40))
{ bill=5*3.0+5*7.0+5*15.0+5*30.0+5*50.0+5*75.0+(table[i]-30)*90.0;
}
else if((table[i]>=41)&&(table[i]<=50))
{ bill=5*3.0+5*7.0+5*15.0+5*30.0+5*50.0+5*75.0+10*90.0+(table[i]-40)*105.0;
}
else if((table[i]>=51)&&(table[i]<=75))
{ bill=5*3.0+5*7.0+5*15.0+5*30.0+5*50.0+5*75.0+10*90.0+10*105.0+(table[i]-50)*110.0;
}
else if(table[i]>75)
{ bill=5*3.0+5*7.0+5*15.0+5*30.0+5*50.0+5*75.0+10*90.0+10*105.0+25*110.0+(table[i]-75)*120.0;
}
ar[i]=bill;
}
}
尽管这有效,但我觉得这是糟糕的编码,如果有 100 个范围会怎样。请建议我另一种更简单的方法来执行此操作,而不是编写简单的 if else 语句。
P.S : 我是初学者,所以请用 C 中的 stdio.h 建议答案。
提前致谢。
你在想这样的事情吗?代码相当简单易懂。如有需要,请随时提出问题。
#include <limits.h> // MAX_INT
#define MIN(a, b) {((a) < (b)) ? (a) : (b);
typedef struct RATE_DEF
{
float slice; // ceiling for this rate - ceiling fro previous rate
float ppu; // price per unit
};
const struct RATE_DEF RATE_TABLE[] =
{
{ 5, 3.f },
{ 5, 7.f },
/* ... */
{ MAX_INT, 120.f }, // much better
};
#define NUM_RATES (sizeof(RATE_TABLE) / sizeof(RATE_TABLE[0]))
void findBill(int table[],float ar[],int size)
{
int i, j, amt, slice;
float bill;
for(i=0; i<7 ; i++)
{
amt = table[i];
bill = 0.f;
for (j = 0; amt > 0 && j < NUM_RATES; ++j)
{
slice = MIN(amnt, RATE_TABLE[j].slice);
bill += (slice * RATE_TABLE[j].ppu);
amt -= slice;
}
ar[i] = bill;
}
[编辑] 有几个错别字,但我今天很懒:)
我编写了一个小程序,它比您当前的示例更具可扩展性。它使用循环,因此它具有 O(n) 时间和 space 复杂性,而您的程序对两者都有恒定的复杂性。尽管如此,我的代码会计算填充任何值的任何大小范围的值。此代码确实需要您在范围内进行实际硬编码,但这相对容易摆脱。
int calcBill(int input){
int total = 0;
int billCost[] = {3,7,15,30,50,75,90,105,110,120};
int billRange[] = {5,10,15,20,25,30,40,50,75,200};
int rangeAdd[10];
int sizeOfRange = sizeof(billCost)/sizeof(int);
//add up the first section
int i = 0;
for(; i<sizeOfRange; i++){
if(i == 0)
rangeAdd[i] = billCost[i] * billRange[i];
else {
rangeAdd[i] = billCost[i] * (billRange[i] - billRange[i-1]);
rangeAdd[i] += rangeAdd[i-1];
}
}
i = 0;
for(; i<sizeOfRange; i++){
if(billRange[i] > input)
break;
}
if(i == 0){
total = input * billCost[0];
}
else {
total += (input - billRange[i-1]) * billCost[i];
if(i > 0)
total += rangeAdd[i-1];
}
printf("%d %d\n", input, total);
return total;
}
此代码使用两个数组(billCost 和 billRange)来计算当您使用给定范围内的所有单位时每张账单的费用。例如,25 个单位的账单存储在 rangeAdd 数组中的索引 4 处,30 个单位的账单存储在索引 5 处。这很容易计算,只需遍历两个数组即可。然后代码找到两个数组的单位所处的最大范围的索引(对于 36 的输入,这将是范围 31-40,或索引 7)。该代码计算该范围内的单位数,并将该范围内的总账单(单位数 * 价格)添加到范围内预先计算的值中,并为其正下方的索引添加值。
显然,如果您 运行 执行此程序数百次,则每次都会重新计算此函数中的 rangeAdd 数组。您可以预先计算它并将其作为变量传递给函数。这只是一个概念证明,可以提高效率。
由于根据单位数量计算成本没有固定模式,因此很难避免值的硬编码数组。
但我认为您所做的实施可以更简洁。
我认为比较好的做法是下面的
void findBill(int table[], float arr[], int size) {
int levels[]={75,50,40,30,25,20,15,10,5,0};
float costs[]={120,110,105,90,75,50,30,15,7,3};
int level_cnt=sizeof(levels) / sizeof(int);
for(int i=0;i<size;i++) {
arr[i]=0;
for(int c=0;c<level_cnt;c++) {
if(table[i]>levels[c]) {
arr[i]+=(table[i]-levels[c])*costs[c];
table[i]=levels[c];
}
}
}
}