根据C中的不均匀范围计算金额

问题描述:

我正在浏览以前的纸质问题,发现一个问题,需要我根据每个客户消耗的单位数量(电力)生成帐单。有一张表格指示如何完成计算。我已经使用if else语句以非常基本的方式制作了该程序。我想知道是否有更好的方法比使用其他方法。也许循环?我尝试使用循环,但它对我来说不切实际,因为范围不是恒定的。 这是该问题一部分的屏幕截图。 Question Screenshot根据C中的不均匀范围计算金额

我创建的函数计算如下。

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中的答案。

+0

一个HashMap是一个选项。另外,到处都有“5 * 3.0 + 5 * 7.0”之类的理由吗?这是一个常数...你可以将这种东西简化为'50.0'。如果这是生产代码,我可能会把它放在一个外部文件中。 –

+0

@ChristopherSchneider:有时候更容易理解,以显示如何计算值。但我同意使用幻数是一个非常糟糕的想法,容易出错。 – Olaf

+0

您被要求传递数组*的大小*作为参数,然后在代码中硬编码了'7'。它应该是'尺寸'。 –

由于没有固定的计算费用的模式,这取决于单元的数量,所以难以避免硬编码的数组值。

但你所做的实现可以更清洁,我认为。

,我认为是更好的方法是以下

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]; 
      } 
     } 
    } 
} 

你在想这样的事情吗?代码非常简单。如有需要,随时提出问题。

#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)的时间和空间复杂性,因为你的程序对于两者都具有不变的复杂性。尽管如此,我的代码会计算任何大小范围内填充任何值的值。这段代码确实需要你在范围内进行实际的硬编码,但这相对容易摆脱。

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单位的账单存储在范围增加数组中的索引4处,30单位的账单存储在索引5处。这很容易计算,只是循环两个数组。代码然后找到你的单位落入这两个数组的最大范围的指数(对于36的输入,即范围31-40或索引7)。该代码计算该范围内的单位数量,并将该范围的总单(单位*价格)添加到其正下方的指数的范围添加值中保存的预先计算的值。

显然,如果你运行这个程序数百次,这个函数中的rangeAdd数组将被重新计算。您可以预先计算并将其作为变量传递给函数。这仅仅是一个概念证明,并且可以变得更有效率。