我和老婆打赌的结果

来源:互联网 发布:商品进销存软件 编辑:程序博客网 时间:2024/04/28 21:40

我们要计算一个滚动投资的结果,需求是这样的:
每点需要200元来购买,每点可以收获26次,每次的收获的金额如下:
第一次10元,第二~第六次20元,第七~第八次30元,第九次38元,第十~第二十六次15元。每半个月收获一次。
滚动投资的意思是,最开始所投资的钱200点,投资日起2006.1.1,那么第一次2006.1.15就收获200*10元(也就是10个点),立即投资,那么到第二次2006.1.30的时候总共获得200*20+200*10/200*10 = 4100元(也就是20点零100元,这一百元因为不够一个点所以留到下次投资)。到2006.2.15所获得的金额200*20+10*20+20*10. 依此类推。

我和老婆打赌,她用Excel表来计算,20分钟,搞定了。每个月的金额,每次的金额,总共投资的金额一目了然。而且可以设定投资的百分比,投资的总金额,开始的时间。很智能。

而我用了她三倍的时间写了一个递归的程序,刚开始执行还好,计算前7个月都没有问题,但是到第8个月左右的时候程序就一直执行了,我仔细一检查发现复杂度太大了,n! ,也就是说在第十次3628800次循环,第十一次就循环次数过亿了,另外因为递归程序局部变量暂用堆栈,所以基本上就不动了。

十分郁闷。

后来我察看了一下递归的资料发现,
 要注意一定要留个出口.其它的就要注意一下时间复杂度或空间复杂度,某些算法(比如二叉树的遍历),在规模不大的情况下用递归不但编码方便,而且系统开销不大,但达到一定规模后用递归系统开销就很大了,这时要注意使用非递归的方法了.

而且所有的递归算法理论上都能修改成非递归算法。

所以我又开始修改成非递归的算法,修改成非递归的一般规律是找到循环的规律,用循环代替。

代码如下:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class test {
 
 int a[] = { 10, 20, 20, 20, 20, 20, 20, 30, 30, 38, 15, 15, 15, 15, 15, 15,
   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 };

 
  
 /**
  * 计算截止到第times次为止(包括第times次),所投入的全部金额(包括第一次投入的)
  * @param times  计算截止到第times次为止(包括第times次)
  * @param invest 最开始投入的金额
  * @return
  */
 public int getAllInvestMoney(int times,int invest){
  List list =  result(times,invest);
  int result = 0 ;
  for (Iterator iter = list.iterator(); iter.hasNext();) {
   Integer num = (Integer) iter.next();
   result+=num.intValue();
  }
  return result;
 }
 
 /**
  * 计算在第times次的时候,所能获得的金额.
  * @param times  计算截止到第times次为止(包括第times次)
  * @param invest 最开始投入的金额
  * @return
  */
 public int getInvestMoney( int times,int invest){
  List list =  result(times,invest);
  Integer result = (Integer)(list.get( list.size()-1));
  return result.intValue();
 }

 /**
  * 显示所有的投资的金额
  * @param times
  * @param invest
  */
 public void showAllInvestInfo( int times,int invest){
  List list =  result(times,invest);
  int j=0;
  for (Iterator iter = list.iterator(); iter.hasNext();) {
   Integer num = (Integer) iter.next();
   System.err.println("第"+j+"次的投资金额="+num.intValue()+"元");
   j++;
  }
  System.err.println("=============over===========");
 }
 
 
 /**
  *
  * @param n 计算到第n次的时候,所有投资的金额组成的列表
  * @param invest 第一次所投资的金额
  * @return
  */
 private List result(int n, int invest) {
  List list = new ArrayList();
  
  list.add(0,new Integer(invest));
  for (int i = 1; i <= n; i++) {
   List tmpList = null;
   if( i<=26 ){
    tmpList = list ;
   }else{
    tmpList = list.subList(i-26,list.size()-1);
   }
   int result = 0;
   int j=0 ;
   for (Iterator iter = tmpList.iterator(); iter.hasNext();) {
    Integer listj = (Integer) iter.next();
    if(iter.hasNext())
     result+=listj.intValue()/200*a[(i-1-j)%26];
    else
     result+=listj.intValue()/200*a[(i-1-j)%26]+listj.intValue()%200;
    j++;
   }
   list.add( new Integer(result));
   
  }

  return list;
 }

 

 /**
  * @param args
  */
 public static void main(String[] args) {
  int times = 18;
  int money = 200*200;
  test obj = new test();
  //显示开始的投资金额以及每次投资的金额
  obj.showAllInvestInfo(times,money);
  //得到第times此的回报金额
  int result = obj.getInvestMoney(times,money);
  System.err.println( "第"+times+"次,就可以投资" +result+"元了" );
  //得到所有的投资金额(包括最初的投资)
  int allInvestMoney = obj.getAllInvestMoney(times,money);
  System.err.println( "加上最初投入的钱("+money+")总共投资"+allInvestMoney +"元");

  
 }

}

以前的递归算法如下:

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeSet;

public class digui {
 
 //第一次投资的钱
 int investMoney = 60000;
 //每点的钱数
 int moneyPerPoint = 200;
 //每点可以投资的最大次数
 static int maxTime = 26;
 //投资日期
 Date investDate = new Date();
 //每次每点所能获得的金额,共26次.
 int a[] = { 10, 20, 20, 20, 20, 20, 20, 30, 30, 38, 15, 15, 15, 15, 15, 15,
   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 };
 //截至的日期(在构造函数中设置)
 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
 public Date breakDate ; // 计算到此日所获得的全部金额
 //到breakDate那天能够获得的金额
 int allMoney = 0;
 
 
 public digui() {
  try {
   //设置你想获得什么时间的金额
   breakDate = sdf.parse("2007-04-19");
  } catch (Exception e) {

  }
 }
 
 /**
  * 计算所有日期的金额,并显示他们.
  *
  */
 public void caculateAllMoney() {
  HashMap map = new HashMap();
  //获得每次的所获金额
  this.caculateDateMoney(this.investDate, this.investMoney,
    this.breakDate, map);
  //按照时间的顺序显示金额
  TreeSet tset = new TreeSet(new DateSort());
  tset.addAll(map.keySet());
  int i = 1;
  for (Iterator iter = tset.iterator(); iter.hasNext();) {
   String dateStr = (String) iter.next();
   System.err.println("第[" + (i++) + "]次投资日期=" + dateStr + ",投资金额="
     + map.get(dateStr));
  }
 }
 
 /**
  * 计算点数,金额/200就是点数
  * @param money
  * @return
  */
 private int caculatePoint(int money) {
  return money / moneyPerPoint;
 }

 /**
  * 递归计算某次投资为止滚动投资的所有投资的金额.
  * @param investDate
  * @param investMoney
  * @param breakDate
  * @param map
  */
 public void caculateDateMoney(Date investDate, int investMoney,
   Date breakDate, Map map) {
  Calendar cld = Calendar.getInstance();
  cld.setTime(investDate);
  for (int i = 0; i < a.length; i++) {
   int money = a[i] * (this.caculatePoint(investMoney));
   cld.add(Calendar.DAY_OF_YEAR, 15);
   if (map.containsKey(sdf.format(cld.getTime()))) {
    Integer tmp = (Integer) map.get(sdf.format(cld.getTime()));
    map.put(sdf.format(cld.getTime()), new Integer(money
      + tmp.intValue()));
   } else {
    map.put(sdf.format(cld.getTime()), new Integer(money));
   }
   if (cld.getTime().after(breakDate)) {
    break;
   } else {
    //滚动计算所有日期的对应的金额
    caculateDateMoney(cld.getTime(), money, breakDate, map);
   }
  }
 }

 

 /**
  * @param args
  */
 public static void main(String[] args) {
  digui obj = new digui();
  obj.caculateAllMoney();
 }

}
/**
 * 用于顺序显示结果.
 * @author eric
 *
 */
class DateSort implements Comparator {
 public int compare(Object a, Object b) {
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  try {
   Date date1 = sdf.parse((String) a);
   Date date2 = sdf.parse((String) b);
   if (date1.after(date2)) {
    return 1;
   } else {
    return -1;
   }
  } catch (Exception e) {
   return -1;
  }

 }
}
所以,大规模时尽量避免递归!!!

原创粉丝点击