带权随机数问题--根据权重随机选择一条路径
最近工作中遇到了一个根据权重随机选择一条路径的问题,一时没有啥好方案,参考借鉴了网上的经验,得出了如下解决方案:
思路:1.求权重的和,对(0,权重之和]区间进行划分,每个权重占用长度为权重的区间;
2.产生一个在(0,权重之和]区间的等概率随机数;
3.该随机数落在哪个区间,则该区间对应的权重的映射为本次产生的带权随机数。
br />
1 import java.util.ArrayList; 2 import java.util.HashMap; 3 import java.util.List; 4 import java.util.Map; 5 import java.util.Random; 6 7 public class WeightRandomTest { 8 public static void main(String[] args) { 9 //数据初始化key:value=权重:值 10 Map<Integer, String> operMap=new HashMap<Integer, String>(); 11 operMap.put(5, "001001"); 12 operMap.put(10, "005001"); 13 operMap.put(40, "004001"); 14 operMap.put(30, "006004"); 15 operMap.put(15, "007003"); 16 17 //实验次数 18 int testCount=100000; 19 20 //求权重的和 21 int sumWeight=0; 22 for(Map.Entry<Integer,String> kv:operMap.entrySet()) 23 sumWeight+=kv.getKey(); 24 25 //随机抽样100000次 26 List<String> res=new ArrayList<String>(); 27 for(int k=0;k<testCount;k++){ 28 //产生0到sumWeight的随机数 29 Random r=new Random(); 30 double randNum=r.nextInt(sumWeight); 31 int stepWeightSum=0; 32 //一次遍历 33 for(Map.Entry<Integer,String> kValue:operMap.entrySet()){ 34 stepWeightSum+=kValue.getKey();//区间(stepWeightSum,stepWeightSum+weights[i]] 35 if(randNum<=stepWeightSum){//选择随机数落在该区间的那个值为随机产生的带权重随机数 36 res.add(kValue.getValue()); 37 break; 38 } 39 } 40 } 41 42 //统计并输出实验结果 43 Map<String, Integer> map=new HashMap<String, Integer>(); 44 Map<String, String> mapP=new HashMap<String, String>(); 45 int value=0; 46 for(String key:res){ 47 if(map.get(key)!=null){ 48 value=map.get(key)+1; 49 map.put(key, value); 50 mapP.put(key,value*100.0/testCount+"%"); 51 } 52 else { 53 map.put(key, 1); 54 mapP.put(key,1*100.0/testCount+"%"); 55 } 56 } 57 System.out.println("次数统计:"+map); 58 System.out.println("概率统计:"+mapP); 59 } 60 } 61 62
实验结果: 63 次数统计:{005001=9977, 006004=29179, 001001=6026, 007003=14986, 004001=39832} 64 概率统计:{005001=9.977%, 006004=29.179%, 001001=6.026%, 007003=14.986%, 004001=39.832%}
实验结论:从实验数据来看,100000次实验,每个值随机出现的概率基本与相应的权重值相符合,除去实验次数循环和实验统计等辅助空间外,算法的时间复杂度为O(n),空间复杂度为O(1)