java实现权重的简单算法

有抽奖自然就有三六九等,自然又是金字塔模式。下面贴出我的demo代码,然后一一解答。文章尾部有我的参考链接,大部分代码来源于他,我只是稍微优化。

import java.util.ArrayList;
import java.util.List;

/**
 * Created by liyang on 2017/7/13.
 */
public class PrizeTest {

    /**
     * 根据Math.random()产生一个double型的随机数,判断每个供应商出现的概率
     * @param prizes
     * @return random:奖品列表prizes中的序列(prizes中的第random个就是抽中的奖品)
     */
    public static int getPrizeIndex(List<Prize> prizes) {
        int random = -1;
        while(random < 0 ) {
            try {
                //计算总权重
                double sumWeight = 0;
                for (Prize p : prizes) {
                    sumWeight += p.getPrize_weight();
                }

                //产生随机数
                double randomNumber;
                randomNumber = Math.random();

                //根据随机数在所有奖品分布的区域并确定哪个供应商
                double d1 = 0;
                double d2 = 0;
                for (int i = 0; i < prizes.size(); i++) {
                    d2 += Double.parseDouble(String.valueOf(prizes.get(i).getPrize_weight())) / sumWeight;
                    if (i == 0) {
                        d1 = 0;
                    } else {
                        d1 += Double.parseDouble(String.valueOf(prizes.get(i - 1).getPrize_weight())) / sumWeight;
                    }
                    if (d1 <= randomNumber && randomNumber < d2) {
                        random = i;
                        break;
                    }
                }
            } catch (Exception e) {
                System.out.println("出错原因:" + e.getMessage());
            }
        }
        return random;
    }

    public static void main(String[] agrs) {
        int i = 0;
        List<Prize> prizes = new ArrayList<Prize>();

        Prize p1 = new Prize();
        p1.setPrize_name("供应商1");
        p1.setPrize_weight(1);//权重设置成1
        prizes.add(p1);

        Prize p2 = new Prize();
        p2.setPrize_name("供应商2");
        p2.setPrize_weight(2);//权重设置成2
        prizes.add(p2);

        Prize p3 = new Prize();
        p3.setPrize_name("供应商3");
        p3.setPrize_weight(3);//权重设置成3
        prizes.add(p3);

        Prize p4 = new Prize();
        p4.setPrize_name("供应商4");
        p4.setPrize_weight(4);//权重设置成4
        prizes.add(p4);
        int[] result=new int[prizes.size()];

        System.out.println("开始.。。");
        for (i = 0; i < 100; i++)// 打印100个测试概率的准确性
        {
            System.out.println("第"+i+"次使用:"+prizes.get(getPrizeIndex(prizes)).getPrize_name());
            result[getPrizeIndex(prizes)]++;
            System.out.println("--------------------------------");
        }
        System.out.println("结束。。。");
        System.out.println("每家供应商的使用数量为:");
        System.out.println("供应商1:"+result[0]);
        System.out.println("供应商2:"+result[1]);
        System.out.println("供应商3:"+result[2]);
        System.out.println("供应商4:"+result[3]);
    }

    static class Prize{
        private String prize_name;//名称
        private int prize_weight;//权重

        public String getPrize_name() {
            return prize_name;
        }

        public void setPrize_name(String prize_name) {
            this.prize_name = prize_name;
        }

        public int getPrize_weight() {
            return prize_weight;
        }

        public void setPrize_weight(int prize_weight) {
            this.prize_weight = prize_weight;
        }
    }
}
  • 第一步:新建一个奖品实体

奖品实体必须含有两个字段,一个用于区分的名称/ID;一个权重

  • 第二步:权重的核心算法
                for (int i = 0; i < prizes.size(); i++) {
                    d2 += Double.parseDouble(String.valueOf(prizes.get(i).getPrize_weight())) / sumWeight;
                    if (i == 0) {
                        d1 = 0;
                    } else {
                        d1 += Double.parseDouble(String.valueOf(prizes.get(i - 1).getPrize_weight())) / sumWeight;
                    }
                    if (d1 <= randomNumber && randomNumber < d2) {
                        random = i;
                        break;
                    }
                }

我用一个表格展示循环的一周期,其中demo为了好计算,4个样例凑了个整数10,概率分别为0.1-0.2-0.3-0.4,实际使用过程中分子分母是分开计算的,不需非得凑整数且允许单个样例权重为0但不能为负数。

次数d1d2概率区间
101/100     --1/10
21/103/101/10--3/10
33/106/103/10--6/10
46/1016/10--10/10

 

 

这里写图片描述

原理就是利用Math.random()每次获取的值0<= x<1的随机分布,从而根据各自的概率比值来实现权重。

double randomNumber;
randomNumber = Math.random();

原文链接:http://blog.csdn.net/huyuyang6688/article/details/50480687

转载于:https://my.oschina.net/ytliyang/blog/1505233

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值