随机发红包底层逻辑演示

本文探讨了两种红包分配方法,第一种基于递减基数可能导致金额分配不均,而第二种采用随机基数分配,确保每个红包公平。作者通过模拟运行结果,强调了改进方法的合理性。
摘要由CSDN通过智能技术生成

#碰到一个练习,需要进行红包的随机分配,如此便有此文。

由于红包的特性,也就是红包个数相加要等于红包的总金额、每个红包随机都不可超过红包的总金额等等。

所以每发一个红包就要从总金额中减去。

一、第一个方法

最直白的暴力分配,分一个红包,总金额减去当前红包的金额,最后一个包则拿走剩余的金额,最终完成分配。

例如:红包总金额=10

第一次红包的分母为红包的总金额,也就是10,如果拿走了5元,剩余5元。

第二次红包的分母为红包的剩余总金额,就变成了5,如果再拿走了3元,剩余2元。

第三次、第四次、第五次的基数就会越来越小,有失公平。

/**
     * 发红包方法
     * 参数1:redPacket为红包总金额
     * 参数2:count为红包个数
     *
     * @param redPacket
     * @param count
     * @return
     */
    public static double[] redPacketDistribution(double redPacket, int count) {
        double[] arr = new double[count];//创建一个数组存储结果
        Random r = new Random();//创建随机数对象
        for (int i = 0; i < count; i++) {//随机红包个数次
            if (i + 1 == count) {
                arr[i] = redPacket;//拿走剩余总额
                redPacket = 0;//总额清零
            } else {
                double tempResult = r.nextDouble(redPacket);//随机获得一个不超过红包大小的值
                String strResult = new DecimalFormat("#.##").format(tempResult);//格式化保留2位
                //精准小数运算
                BigDecimal bdV = BigDecimal.valueOf(Double.parseDouble(strResult));//当前红包金额
                BigDecimal bdRedPacket = BigDecimal.valueOf(redPacket);//红包总额
                redPacket = Double.parseDouble(bdRedPacket.subtract(bdV).toString());//红包总金额减去当前红包金额
                arr[i] = Double.parseDouble(bdV.toString());
            }
        }
        return arr;
    }

运行结果一

运行结果二

运行结果三

结论:通过多次模拟的运行结果以及代码逻辑来看,红包的分配并不均匀,金额大的往往在前。说明此方法的逻辑存在明显问题。

二、第二个方法

第二个方法,参考了热心网友的思路,加以改进,步骤如下。

首先对每个包设定一个随机的值,作为分子,而红包总数的随机值则为分母,简单来讲就是将红包分为若干个不等值。基数我设定为了红包总金额*红包总个数,当然这个基数没有依据,但是我认为不能过大也不能过小,要与红包的总金额和总个数相关,所欲采用这个值为基数。

这个方法的好处我认为是没有领红包的先后顺序,所以不会发生上一种方法那样结果极不均匀的情况,对于每个红包来讲都是公平的。

例如

第1个红包的随机基数为5
第2个红包的随机基数为32
第3个红包的随机基数为47
第4个红包的随机基数为35
第5个红包的随机基数为25

而他们的总基数就为他们的和,也就是144,将红包的总金额平均分为144份,每个红包按照他们的随机基数进行分配。

/**
     * 发红包方法
     * 参数1:redPacket为红包总金额
     * 参数2:count为红包个数
     *
     * @param redPacket
     * @param count
     * @return
     */
    public static double[] redPacketDistribution(double redPacket, int count) {
        double[] arr = new double[count];//创建一个数组存储结果
        Random r = new Random();//创建random

        int randomSum = 0;//定义随机总值
        for (int i = 0; i < count; i++) {//循环获得count个随机值
            int res = r.nextInt((int) redPacket * count);//基数为红包总额*红包个数
            arr[i] = res;//赋值给结果数组
            randomSum += res;//随机总值累加
        }

        for (int i = 0; i < count; i++) {//循环红包个数次
            if (i + 1 == count) {//最后一个包
                arr[i] = redPacket;//拿走剩余总额
                redPacket = 0;//总额清零
            } else {
                double tempResult = redPacket * arr[i] / randomSum;//获得随机金额
                DecimalFormat df = new DecimalFormat("#.##");//创建格式化
                String strResult = df.format(tempResult);//保留2位
                double result = Double.parseDouble(strResult);//转回double
                //精准小数计算
                BigDecimal bdRedPacket = BigDecimal.valueOf(redPacket);
                BigDecimal bdResult = BigDecimal.valueOf(result);
                redPacket = Double.parseDouble(bdRedPacket.subtract(bdResult).toString());//红包总额=红包总额-此次的随机金额
                arr[i] = result;//将此次随机金额放入数组
            }
        }
        return arr;
    }

运行结果一

运行结果二

运行结果三

结论:通过多次的模拟结果以及思路,这个方法是相对比较合理的,每个红包获得不同的值的概率基本相同。

2024元旦跨年夜写下此文,祝新年快乐。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值