最近在一个分销系统,无限级别的,需要用递归遍历,之前发布的那篇博文代码上有问题,但算法是没问题,看过的读者请更正下,上篇博文地址如下
在网上也看了相关递归的算法,很多人建议用循环+堆栈替换递归,以防止栈溢出。
这里就不做比较了,感兴趣的读者可以搜下。
调用了递归的过程中用了if(){}else{},然后想用return结束循环需要特别注意,这次就遇到这个坑,只能说自己对递归的算法不是很了解。
递归的四条基本法则:(引自《数据结构与算法分析——C语言描述》Mark Allen Weiss 著)
1. 基准情形。
2. 不断推进。
3. 设计法则。
4. 合成效益法则。
这里说下return的作用域,
return 对当前函数来说是结束了,对调用它的父函数来说你这个函数执行完成了,父函数就会接着执行下一语句。
没想到父函数马上又遇到一个return,父函数结束了,对爷爷函数来说父函数执行完成了,爷爷函数就接着执行下一个语句
没想到。。。
没想到。。。
完,回到最初调用递归函数的地方。
该函数的基准情形就是 num <= 1 的情况,这种情况下,无需递归就能解出,也就是直接返回1.
而 return numfact(num-1); 则是“不断推进”。 return 8fact(8-1); 则需要知道fact(7),要知道fact(7),则需要return 7fact(7-1); 要知道fact(6),则需要return 6fact(6-1); .。。。如此下去,直到遇到“基准情形”。前面的父函数,爷爷函数比喻的很形象。
所以在之前的地方加了个return就得到正确的结果了,修改过的代码如下:
/**
* 统计代理商自身分润
*
* @param userList 代理商列表,有上下级关系
* @param userListB 代理商列表,无上下级关系
* @return 代理商列表
*/
private List<User> countTree(List<User> userList, List<User> userListB) {
for (User userA : userList) {
Double fee = 0.0; //总佣金
Double split = 0.0; //上下级分润比例差
if (!CollectionUtils.isEmpty(userA.getWb_type()) && !CollectionUtils.isEmpty(userA.getFs_user_id())) {
fee = MoneyUtil.multiply(userA.getWb_type(), userA.getFs_user_id());//根据结算依据计算A自身商户分润
}
if (userA.getSo_child().equals("1")) {
Double FsCode = 0.0; //下级贡献给上级代理商分润A
Double fsCodeFee = 0.0; //代理结算依据汇总(元)A
if (!CollectionUtils.isEmpty(userListB)) {
for (User userB : userListB) {
if (userB.getSo_id().equals(userA.getSu_id())) {
if (!CollectionUtils.isEmpty(userA.getWb_type()) && !CollectionUtils.isEmpty(userB.getWb_type())) {
split = MoneyUtil.subtract(userA.getWb_type(), userB.getWb_type());
}
if (userB.getSo_child().equals("1")) {
fsCodeFee = MoneyUtil.add(fsCodeFee, MoneyUtil.convertDouble(userB.getFs_user_id()), 4, MoneyUtil.ROUND_HALF_UP);//代理结算依据(元)+B
fsCodeFee = countRecursion(fsCodeFee, userListB, userB.getSu_id());//根据结算依据计算C级以下分润
FsCode =MoneyUtil.multiply(fsCodeFee, split, 4, MoneyUtil.ROUND_HALF_UP);//计算下级贡献给上级代理商分润
} else {
fsCodeFee = MoneyUtil.add(fsCodeFee, MoneyUtil.convertDouble(userB.getFs_user_id()), 4, MoneyUtil.ROUND_HALF_UP);//代理结算依据(元)+B
FsCode = MoneyUtil.add(FsCode, MoneyUtil.multiply(split, fsCodeFee, 4, MoneyUtil.ROUND_HALF_UP));//根据结算依据计算B分润
}
}
}
fee = MoneyUtil.add(FsCode, fee, 4, MoneyUtil.ROUND_HALF_UP);
}
userA.setFs_code(MoneyUtil.roundDouble(String.valueOf(FsCode), 4, MoneyUtil.ROUND_HALF_UP));
userA.setFs_code_fee(MoneyUtil.roundDouble(String.valueOf(fsCodeFee), 4, MoneyUtil.ROUND_HALF_UP));
}
userA.setFs_fee_split(MoneyUtil.roundDouble(String.valueOf(fee), 4, MoneyUtil.ROUND_HALF_UP));
}
return userList;
}
/**
* 用递归遍历代理商,并统计分佣
* @see return countRecursion(fsCodeFee, userList, user.getSu_id());//这里的return很重要,用于跳出循环
* @param fsCodeFee 代理商商户流水统计
* @param userList 代理商列表
* @param so_id 父级代理ID
* @return 总佣金
*/
private Double countRecursion(Double fsCodeFee, List<User> userList, String so_id) {
for (User user : userList) {
if (user.getSo_id().equals(so_id)) {
if (user.getSo_child().equals("1")) {
fsCodeFee = MoneyUtil.add(fsCodeFee, MoneyUtil.convertDouble(user.getFs_user_id()), 4, MoneyUtil.ROUND_HALF_UP);代理结算依据(元)+C
return countRecursion(fsCodeFee, userList, user.getSu_id());
} else {
fsCodeFee = MoneyUtil.add(fsCodeFee, MoneyUtil.convertDouble(user.getFs_user_id()), 4, MoneyUtil.ROUND_HALF_UP);//代理结算依据(元)+C
}
}
}
return fsCodeFee;
}