zoukankan      html  css  js  c++  java
  • 微信红包是怎么实现的

    微信红包的实现方式是怎么样的?

      微信红包的思路:

        每个人当前抢到的微信红包金额大小服从:区间[0.01,2*当前剩余红包均值两倍)上的均匀分布。可能不太好理解,举个例子:某个时刻你抢到了红包,在你抢红包前红包余额为m,红包剩余个数为n,那么你抢到的金额一定是在[0.01,2*m/n)区间内,其中m/n就是你抢红包前每个人可以均分到的红包金额,即剩余红包均值。

      微信红包算法应该主要考虑以下几个因素:
        1.微信红包金额是随机数:只不过这个随机数有限制:精确到两位小数;最小金额是0.01;最大金额也有限制:2倍的剩余红包平均金额.
        2.不能超发,就是你发了3块钱红包最后红包总额不能超过3块。
        3.先抢和后抢的收益均值要大致相同
      基于上面几点,博主写了一份示例代码,如下:(代码地址:https://github.com/LoveWK/JavaBase.git):/src/com/wk/WeChatRedPackage/
      1 /**
      2  * 〈一句话功能简述〉<br> 
      3  * 〈微信红包的实现原理〉
      4  *
      5  * @author wangkai_wb
      6  * @create 2020/6/9
      7  * @since 1.0.0
      8  * 微信红包算法应该主要考虑以下几个因素:
      9  * 1.微信红包金额是随机数
     10  *  只不过这个随机数有限制:精确到两位小数;最小金额是0.01;
     11  *  最大金额也有限制:2倍的剩余红包平均金额(2倍的数据是毕导视频给出的)
     12  * 2.不能超发,就是你发了3块钱红包最后红包总额不能超过3块。
     13  * 3.先抢和后抢的收益均值要大致相同
     14  */
     15 public class WeChatRedPackage {
     16     public static void main(String[] args) {
     17         //设置红包总金额参数
     18         double sum = 0;
     19         //定义Map集合,用于获取每个人对应的金额
     20         Map<String,Double> map = new HashMap<>();
     21         //定义一个list集合,用于获取运气王
     22         List list = new ArrayList();
     23         //获得红包分配的数组集合
     24         ArrayList<Double> res = WXRedPackageAlgorithm(10,3);
     25         //遍历集合
     26         for (int i = 0; i <res.size() ; i++) {
     27             double money = res.get(i);
     28             sum += money;
     29             System.out.println("第"+i+"个人获得:"+money+"元");
     30             //将每个人获取的值传到map中
     31             map.put("第"+i+"个人",money);
     32         }
     33         System.out.println("红包已被领完");
     34         System.out.println();
     35         System.out.println("红包总金额为:"+sum+"元");
     36         //按升序排序
     37         Map<String,Double> sortedMap =sortByValue(map);
     38         sortedMap.forEach((key, value)->{
     39 //            System.out.println(key+":"+value);
     40             list.add(key);
     41         });
     42         System.out.println();
     43         System.out.println("恭喜"+list.get(0)+"成为运气王,获得金额:"+sortedMap.get(list.get(0))+"元");
     44     }
     45 
     46     /**
     47      * 红包分配的数组集合
     48      * @param restMoney 红包总额
     49      * @param restNum 分给的人数
     50      * @return
     51      */
     52     private static ArrayList<Double> WXRedPackageAlgorithm(double restMoney,int restNum){
     53         //根据需要分配的人数进行红包总金额的分配
     54         ArrayList<Double> res = new ArrayList<>(restNum);
     55         // 生成随机数工具
     56         Random random = new Random();
     57 
     58         while (restNum >1){
     59             // 最大的红包为:两倍的平均红包大小
     60             double max = (restMoney/restNum)*2;
     61             // 产生[0,1)之间的随机数
     62             double r = random.nextDouble();
     63             // 抢到的红包区间[0,max)
     64             double money = r*max;
     65             if(money<0.01)
     66                 money = 0.01;
     67             else//floor方法:返回最大的(最接近正无穷大)double 值,该值小于等于参数,并等于某个整数。
     68                 money = Math.floor(money*100)/100;
     69             res.add(money);
     70 
     71             restNum--;
     72             //剩余总金额 = 总金额-已经获取红包的金额
     73             restMoney -= money;
     74         }
     75         //最后一个红包为剩余余额
     76         res.add(Math.floor(restMoney*100)/100);
     77         return res;
     78     }
     79 
     80     /**
     81      * 对map集合进行降序排序,为了获得运气王
     82      * @param map
     83      * @param <K>
     84      * @param <V>
     85      * @return
     86      */
     87     private static <K,V extends Comparable<? super V>> Map<K,V> sortByValue(Map<K,V> map){
     88         //创建一个链表集合
     89         List<Map.Entry<K,V>> list = new LinkedList<>(map.entrySet());
     90         //使用集合类的排序方法
     91         Collections.sort(list, new Comparator<Map.Entry<K, V>>() {
     92             @Override
     93             public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
     94                 //按降序排序,如果不加前面的-号,就是升序排序
     95                 return -(o1.getValue().compareTo(o2.getValue()));
     96             }
     97         });
     98         //遍历list,分离出map,使用另一个map集合接收拍好序的集合
     99         Map<K,V> result = new LinkedHashMap<>();
    100         for (Map.Entry<K,V> entry : list){
    101             result.put(entry.getKey(),entry.getValue());
    102         }
    103         return result;
    104     }
    105 }

    运行结果:

       上面有个问题是double类型运算时精度不足会导致,红包总金额为10,红包数量为3时,上面给出的代码跑出的结果可能最后用户只领到了9.99,解决这个问题可以采用java的BigDecimal类来解决精度问题。对于不需要任何准确计算精度的数字可以直接使用float或double,但是如果需要精确计算的结果,则必须使用BigDecimal类,而且使用BigDecimal类也可以进行大数的操作,有兴趣的同学可以试试改进下上面代码。

  • 相关阅读:
    API入门系列之三 那迷惑人的Windows字符和字符指针类型 转载
    laravel中关联模型查询选择性的字段
    【实习】微软PM实习生面经
    【C++学习】String类的基本用法
    sql server cast 和 convert函数使用
    JS,Jquery获取,dropdownlist,checkbox 下拉列表框的值
    Buffer
    SQL Server 2012新增的内置函数尝试
    SQL Server2012新特性WITH RESULT SETS
    ros(8)自定义service数据
  • 原文地址:https://www.cnblogs.com/wk-missQ1/p/13074343.html
Copyright © 2011-2022 走看看