java語(yǔ)言實(shí)現(xiàn)權(quán)重隨機(jī)算法完整實(shí)例
前言
現(xiàn)在app就是雨后春筍,嗖嗖的往外冒啊,有經(jīng)驗(yàn)的、沒(méi)經(jīng)驗(yàn)的、有資歷的、沒(méi)資歷的都想著創(chuàng)業(yè),創(chuàng)業(yè)的90%以上都要做一個(gè)app出來(lái),好像成了創(chuàng)業(yè)的標(biāo)配。
做了app就得推廣啊,怎么推,發(fā)券送錢是最多用的被不可少的了,現(xiàn)在好多產(chǎn)品或者運(yùn)營(yíng)都要求能夠隨機(jī)出優(yōu)惠券的金額,但是呢又不能過(guò)于隨機(jī),送出去的券都是錢嗎,投資人的錢,是吧。
所以,在隨機(jī)生成的金額中就要求,小額度的幾率要大,大額度的幾率要小,比如說(shuō)3元的70%,5塊的25%,10塊的5%,這個(gè)樣子的概率去生成優(yōu)惠券,這個(gè)怎么辦呢?
對(duì)于上述的問(wèn)題,直接用我們的Random.next(Integer range);就不夠了。因?yàn)檫@個(gè)偽隨機(jī)不帶權(quán)重,3,5,10出現(xiàn)的概率都是一樣的。
實(shí)現(xiàn)思路
還是拿上述的例子,3出現(xiàn)的概率是70%,我們給他的權(quán)重賦值為70,5出現(xiàn)的概率為25%,我們給他的權(quán)重賦值為25,10出現(xiàn)的概率為5%,我們給他的權(quán)重賦值為5.
我們按照順序計(jì)算出權(quán)重的加和,把當(dāng)前數(shù)字出現(xiàn)的權(quán)重加和前的值作為其權(quán)重范圍的起點(diǎn)值,把加和后的值作為其權(quán)重范圍的終點(diǎn)值。
這樣的話,我們就可以使用Random.next(100)來(lái)做隨機(jī)數(shù),然后判斷隨機(jī)數(shù)落在的范圍,然后映射到對(duì)應(yīng)的優(yōu)惠券數(shù)值即可。
java實(shí)現(xiàn)
package com.nggirl.test.weight.random; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Random; public class WeightRandom { public static void main(String[] args){ WeightRandom wr = new WeightRandom(); wr.initWeight(new String[]{ "1","2","3","4" } , new Integer[]{ 100,100,200,600 } ); Random r = new Random(); for (int i = 0; i < 10; i++){ Integer rv = r.nextint(wr.getMaxRandomValue()); System.out.println(rv); System.out.println(wr.getElementByRandomValue(rv).getKey() + " " + rv); } HashMap<String, Integer> keyCount = new HashMap<String, Integer>(); keyCount.put("1", 0); keyCount.put("2", 0); keyCount.put("3", 0); keyCount.put("4", 0); for (int i = 0; i < 10000; i++){ Integer rv = r.nextint(wr.getMaxRandomValue()); String key = wr.getElementByRandomValue(rv).getKey(); keyCount.put(key, keyCount.get(key).intValue()+1); } System.out.println(""); } private List<WeightElement> weightElements; public void initWeight(String[] keys, Integer[] weights){ if(keys == null || weights == null || keys.length != weights.length){ return; } weightElements = new ArrayList<WeightElement>(); for (int i=0; i< keys.length; i++){ weightElements.add(new WeightElement(keys[i], weights[i])); } rangeWeightElemnts(); printRvs(); } private void rangeWeightElemnts(){ if(weightElements.size() == 0){ return; } WeightElement ele0 = weightElements.get(0); ele0.setThresholdLow(0); ele0.setThresholdHigh(ele0.getWeight()); for (int i = 1; i < weightElements.size(); i++){ WeightElement curElement = weightElements.get(i); WeightElement preElement = weightElements.get(i - 1); curElement.setThresholdLow(preElement.getThresholdHigh()); curElement.setThresholdHigh(curElement.getThresholdLow() + curElement.getWeight()); } } public WeightElement getElementByRandomValue(Integer rv){ //因?yàn)樵貦?quán)重范圍有序遞增,所以這里可以改為二分查找 for (WeightElement e:weightElements){ if(rv >= e.getThresholdLow() && rv < e.getThresholdHigh()){ return e; } } return null; } public Integer getMaxRandomValue(){ if(weightElements == null || weightElements.size() == 0){ return null; } return weightElements.get(weightElements.size() - 1).getThresholdHigh(); } public void printRvs(){ for (WeightElement e:weightElements){ System.out.println(e.toString()); } } static class WeightElement{ /** * 元素標(biāo)記 */ private String key; /** * 元素權(quán)重 */ private Integer weight; /** * 權(quán)重對(duì)應(yīng)隨機(jī)數(shù)范圍低線 */ private Integer thresholdLow; /** * 權(quán)重對(duì)應(yīng)隨機(jī)數(shù)范圍高線 */ private Integer thresholdHigh; public WeightElement(){ } public WeightElement(Integer weight){ this.key = weight.toString(); this.weight = weight; } public WeightElement(String key, Integer weight){ this.key = key; this.weight = weight; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public Integer getWeight() { return weight; } public void setWeight(Integer weight) { this.weight = weight; } public Integer getThresholdLow() { return thresholdLow; } public void setThresholdLow(Integer thresholdLow) { this.thresholdLow = thresholdLow; } public Integer getThresholdHigh() { return thresholdHigh; } public void setThresholdHigh(Integer thresholdHigh) { this.thresholdHigh = thresholdHigh; } public String toString(){ return "key:"+this.key + " weight:" + this.weight + " low:"+this.thresholdLow+" heigh:"+this.thresholdHigh; } } }
結(jié)果:
2 102 876 4 876
二分法的實(shí)現(xiàn)
public WeightElement getElementByRandomValue(Integer rv){ if(rv < 0 || rv > getMaxRandomValue()-1){ return null; } //此時(shí)rv必然在0 - getMaxRandomValue()-1范圍內(nèi), //也就是必然能夠命中某一個(gè)值 int start = 0, end = weightElements.size() - 1; int index = weightElements.size()/2; while(true){ if(rv < weightElements.get(index).getThresholdLow()){ end = index - 1; } else if(rv >= weightElements.get(index).getThresholdHigh()){ start = index + 1; } else{ return weightElements.get(index); } index = (start + end)/2; } }
下面再分享一則實(shí)例,加強(qiáng)對(duì)權(quán)重隨機(jī)算法的理解,一次到位!
權(quán)重隨機(jī)算法在抽獎(jiǎng),資源調(diào)度等系統(tǒng)中應(yīng)用還是比較廣泛的,一個(gè)簡(jiǎn)單的按照權(quán)重來(lái)隨機(jī)的實(shí)現(xiàn),權(quán)重為幾個(gè)隨機(jī)對(duì)象(分類)的命中的比例,權(quán)重設(shè)置越高命中越容易,之和可以不等于100;
簡(jiǎn)單實(shí)現(xiàn)代碼如下:
import java.util.ArrayList; import java.util.List; import java.util.Random; public class WeightRandom { static List<WeightCategory> categorys = new ArrayList<WeightCategory>(); private static Random random = new Random(); public static void initData() { WeightCategory wc1 = new WeightCategory("A",60); WeightCategory wc2 = new WeightCategory("B",20); WeightCategory wc3 = new WeightCategory("C",20); categorys.add(wc1); categorys.add(wc2); categorys.add(wc3); } public static void main(String[] args) { initData(); Integer weightSum = 0; for (WeightCategory wc : categorys) { weightSum += wc.getWeight(); } if (weightSum <= 0) { System.err.println("Error: weightSum=" + weightSum.toString()); return; } Integer n = random.nextint(weightSum); // n in [0, weightSum) Integer m = 0; for (WeightCategory wc : categorys) { if (m <= n && n < m + wc.getWeight()) { System.out.println("This Random Category is "+wc.getCategory()); break; } m += wc.getWeight(); } } } class WeightCategory { private String category; private Integer weight; public WeightCategory() { super(); } public WeightCategory(String category, Integer weight) { super(); this.setCategory(category); this.setWeight(weight); } public Integer getWeight() { return weight; } public void setWeight(Integer weight) { this.weight = weight; } public String getCategory() { return category; } public void setCategory(String category) { this.category = category; } }
結(jié)果:
總結(jié)
以上就是本文關(guān)于java語(yǔ)言實(shí)現(xiàn)權(quán)重隨機(jī)算法完整實(shí)例的全部?jī)?nèi)容,希望對(duì)大家有所幫助。如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!
相關(guān)文章
SpringBoot+VUE實(shí)現(xiàn)數(shù)據(jù)表格的實(shí)戰(zhàn)
本文將使用VUE+SpringBoot+MybatisPlus,以前后端分離的形式來(lái)實(shí)現(xiàn)數(shù)據(jù)表格在前端的渲染,具有一定的參考價(jià)值,感興趣的可以了解一下2021-08-08SpringBoot四大神器之Auto onfiguration的使用
本文主要介紹了SpringBoot四大神器之Auto Configuration,springboot auto configuration的本質(zhì)就是自動(dòng)配置spring的各種bean。感興趣的可以了解一下2021-10-10mybatis高級(jí)映射一對(duì)多查詢實(shí)現(xiàn)代碼
本篇文章主要介紹了mybatis高級(jí)映射一對(duì)多查詢實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-04-04WebDriver中實(shí)現(xiàn)對(duì)特定的Web區(qū)域截圖方法
這篇文章主要介紹了WebDriver中實(shí)現(xiàn)對(duì)特定的Web區(qū)域截圖方法,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-06-06解決MyEclipse中Maven設(shè)置jdk版本jdk1.8報(bào)錯(cuò)問(wèn)題
今天安裝了jdk1.8、tomcat8、和maven3.5.2,弄好后在myeclipse新建了一個(gè)maven項(xiàng)目,項(xiàng)目默認(rèn)是jdk1.5,改成jdk1.8后項(xiàng)目報(bào)錯(cuò)2018-10-10關(guān)于@SpringBootApplication與@SpringBootTest的區(qū)別及用法
這篇文章主要介紹了關(guān)于@SpringBootApplication與@SpringBootTest的區(qū)別及用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01