java实现阶梯价算法

一 引言

       工作上的原因需要实现一个阶梯价的算法。


       比如说水的价格是     阶梯周期1月1日到12月31日    100吨以下  1元/吨     100吨到200吨  1.2元/吨  200吨以上   2元/吨

假设用户1月份使用了100吨水,2月份使用了100吨水,3月份也使用了100吨水,那么1月份的账单是  100元,2月份的账单是120,3月份的账单是 200元。


       现在的需求是给你一个周期起始累积量,然后一个用水的吨数,希望能计算出金额。还是上面的例子,起始周期累积量是 100吨,用水量是150吨,那么100吨

会按照1.2元/吨来结算,50吨会按照2元/吨来结算,金额是220元。


       如果价格能给定死的话,就像上边的 1元/吨,2元/吨,3元/吨的例子,算法是非常简单的。但是现实场景中,价格不是固定的,阶梯之间的分界(上例100,200等)

也不是固定的,阶梯的阶数也不是固定的。此外,也可能是固定的一个价格(非阶梯)。


二 实现思路

         还是按照上面的例子,考虑如何实现,用水量从   100吨到250吨共花费多少

         换个方式,100吨到250吨的花费=0到250吨的花费-0到100吨的花费       (可以使用上边的例子计算下,220元=320元-100元),我只需要提供一个方法计算0到100的花费或者

0到250的花费。然后两者的计算结果相减。

        考虑非阶梯没有阶梯分界,为了统一起见,加入一个阶梯分界,Integer.MAX,至此,单价也可以认为是阶梯价      0-Integer.MAX 固定单价    Integer.MAX 以上,因为用不到,也不用关心。


三 java实现


package com.huhj;


import java.math.BigDecimal;
import java.util.LinkedList;
import java.util.List;

public class LadderPriceDemo {
	
	
	public static void main(String[] args){
		
		List<BigDecimal> price=new LinkedList<BigDecimal>();
		List<BigDecimal> vol=new LinkedList<BigDecimal>();
		
		price.add(new BigDecimal("1.0"));
		price.add(new BigDecimal("1.2"));
		price.add(new BigDecimal("2.0"));
		
		vol.add(new BigDecimal("100"));
		vol.add(new BigDecimal("200"));
		
		System.out.println(getMoney(new BigDecimal("100"),new BigDecimal("150"),price,vol));
		
	}
	
	/**
	 * 
	 * @param cycNum   起始周期累积量
	 * @param userNum  用气量
	 * @param price    价格信息, 1,1.2,2
	 * @param vol      阶梯分界    100 200 
	 * @return
	 */
	public static BigDecimal 
	   getMoney(BigDecimal cycNum,BigDecimal useNum,List<BigDecimal> price,List<BigDecimal> vol){
		return            getMoney(cycNum.add(useNum), price, vol)
				.subtract(getMoney(cycNum,price,vol));
	}
	
	/**
	 * 获得0到指定量之间的金额
	 * @param num
	 * @param price
	 * @param vol
	 * @return
	 */
	private static BigDecimal 
	    getMoney(BigDecimal num,List<BigDecimal> price,List<BigDecimal> vol1){
		BigDecimal money=new BigDecimal("0");
		List<BigDecimal> vol=new LinkedList<BigDecimal>();
		vol.addAll(vol1);
		vol.add(0, new BigDecimal("0"));
		vol.add(new BigDecimal(Integer.MAX_VALUE));
		//i用于确定当前的气量在哪个区间,单价的话i是1
		for(int i=0;i<vol.size();i++){
			if( num.compareTo(vol.get(i))>=0  &&   num.compareTo(vol.get(i+1))<0 ){
				//找到指定的区间了
				for(int j=0;j<=i;j++){
					
					if(j!=i){
						money=money.add((vol.get(j+1).subtract(vol.get(j))).multiply(price.get(j)));
					}else{
						money=money.add((num.subtract(vol.get(j))).multiply(price.get(j)));
					}
					
				}
				
				break;
			}
		}
		
		return money;
	}

}