2016-1-17 博客文章增加了markdown格式,由MD标记

2016-04-09 18:13:38

迭代是更新变量的旧值。迭代是一个环结构,每次迭代都是一个圈,不会拉掉其中的某一步,然后不断循环
每个节点都会被循环访问

递归是在函数内部调用自身。递归是一个树结构,每个分支都探究到最远,发现无法继续的时候往回走
每个节点只会访问一次。

下面是我工作中遇到的实例,感觉这种例子比较常用,遂记之。


一:积分消费

需求:

现积分来源有以下两种:

  1. 客户端激励用户行为(连续多少天登录,发布心情,转发文章等)而赠送的积分,会过期而作废。

  2. 用户自行付费购买的积分,不会过期。

当用户利用积分消费时,系统将自动扣除过期时间较近的积分。赠送积分消费完,将开始扣除购买的积分。


分析:

不管该用户有多少种积分。积分扣减过程,都是按如下流程来走的:

step1 

找到未消费完,即只消费一部分的积分记录。开始进行积分消费。

step2 

第一笔记录里积分足够时,就直接从记录里扣减积分。扣减积分流程结束。

第一笔记录里积分刚刚好时,将该记录积分置为0,并标志状态为已消费完。

第一笔记录里积分不够时,就开始继续扣除下一笔积分记录。这样就又回到了step1.


准备工作:

准备工作是为了能够直接套用模型解决问题。按照需求,积分消费类型,需按如下类型排序,优先级依次降低:

未消费完,只消费一部分的积分;

会过期的积分;
不会过期的积分。

为了方便,直接用一状态栏位标注各种状态的积分。

1代表未消费完的积分。

2代表还没开始消费的会过期的积分。

8代表还没开始消费的不会过期的积分。安排为8,是为了防止需求有变,会过期的积分也要分类型。

0代表当前记录的积分已消费完。

如此已安排,直接查询出状态大于0并按状态和有效期一起升序排序的结果。然后遍历结果就可采用迭代方法解决了。


伪代码:

list 用户积分记录集
consume_point 消费的积分额
point 用户单笔积分记录的积分额

foreach(list as item ){
    if( consume_point < point ){
         在item里积分值扣减掉consume_point,记录状态设为1
         break;
    }elseif( consume_point = point){
         将item里积分置为0,状态设为0,表示已消费完
         break;
    }else{
         //下一次要消费的积分,被用到下一次循环即为所说的迭代
         consume_point = consume_point - point;  
    }
}



二:库存出库

需求:

商品采购入库时,可能有多笔采购记录,过期时间可能不尽相同。 订单产品发货出库时,要先扣除过期时间较近的库存,并告知扣除是否成功。如此的目的就是为了更准确的留意产品的保质期,从而及早的采取促销措施来降低产品过期带来的经济损失。


分析:

step1:从过期时间最早的库存记录中扣除记录(销空的排除)。

            当足够扣除时,扣除行为结束,记状态为正在扣除的状态。

            当刚好扣除时,扣除行为结束,记状态为已销空的状态。

            当前记录不够扣除时,继续找出过期时间最早的库存记录(销空的排除),进行如上流程。


准备工作:

本示例采用过期时间排序。所以准备工作,就是确保每一笔采购记录有过期时间。国内产品多是生产日期+保质期的方式。去了一趟马来,那边商品都是生产日期和过期时间一起标注的,貌似欧洲那边也是如此。


伪代码:

出库的产品id product_id
要出库的库存量 ex_qty
采购单笔记录的库存量 p_qty

function deductStock( product_id, ex_qty ){
    
    item = 根据product_id从采购数据里找出保质期最早的记录;
    if( ex_qty < p_qty ){
        扣除当前采购记录里的库存,并标注状态为正在销售的状态
        return true or false.
    }elseif( ex_qty = p_qty ){
        //为了保留采购历史,多加个剩余库存栏位
        置当前采购记录剩余库存为0,并标注状态为已经售罄。
        return true or false.
    }else{
        ex_qty = ex_qty - p_qty; //迭代变量
        return deductStock(product_id, ex_qty); //递归方法
        
    }

}

此处递归里需注意的是返回值,在最后else里也要加return关键词。由于递归是开始从外往里进入执行,然后又由里往外退出,所以我们最终接收到的返回值是由else里返回,而else里返回值则由if,elseif这两种情形返回。


现在两实例的区别,也教明显了。积分消费里伪代码是将可用的积分记录一次性查询出来。而产品出库里则是每次只查询出保质期最早的一笔未售空的采购记录。至于是哪一种效率更好,就是我们要权衡的事情啦。