微信红包是怎么实现的
Posted WK_BlogYard
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微信红包是怎么实现的相关的知识,希望对你有一定的参考价值。
微信红包的实现方式是怎么样的?
微信红包的思路:
每个人当前抢到的微信红包金额大小服从:区间[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类也可以进行大数的操作,有兴趣的同学可以试试改进下上面代码。
以上是关于微信红包是怎么实现的的主要内容,如果未能解决你的问题,请参考以下文章