高并发抢红包系统红包随机金额生成算法
生活随笔
收集整理的這篇文章主要介紹了
高并发抢红包系统红包随机金额生成算法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
本文介紹高并發搶紅包系統中,必不可少的紅包隨機金額生成算法。
假定我們采用預生成方式(相對的還有實時生成,如微信紅包),算法的輸入和輸出如下:
- 給定總金額M和總人數N,采用某種算法生成紅包隨機金額列表
算法要求:
- 隨機金額列表的金額之和,不能超也不能少,恰好等于總金額M
- 每個人至少搶到1分錢
- 所有人搶到金額的幾率是相等的,不能有些人搶到金額的幾率大,而有些人搶不到紅包的幾率大
紅包隨機金額生成算法通常采用二倍均值法,如下是該算法的簡介:
- 剩余總金額M/剩余總人數N,將結果*2得到邊界值E,然后在(0,E)之間得到一個隨機數R,R就是要求的隨機金額
- 將剩余金額進去此時生成的隨機金額R,將剩余人數減1
- 循環執行上述操作,直到剩余人數為0
- 這里要確保生成的所有隨機金額之和,要等于一開始的總金額
如果還想將生成的隨機金額列表再隨機一點,可以再進行打散:
- 因為二倍均值法的算法本質,通常生成的第一個金額會偏大,生成的最后一個金額會偏小。舉個例子,100分錢,5個人分,第一個隨機金額在[1分,40)區間生成,極端情況下可以獲取39分錢。如果前面的人正好瓜分了99分錢,那么最后一個人只能得到1分錢。因此對這種情況有避諱的話可以再打散
- 如何打散?可以針對每個隨機金額生成一個排序值,然后按排序值從小到大或從大到小排序都可以,排序后的隨機金額列表就更具有隨機性了
我們將金額單位設為分,這樣的話發紅包的總金額和每個人搶到的紅包金額都可以精確到1分錢;金額變量整數形式(用元做單位就要用小數了,小數在做計算時容易丟失精度),且確保搶到紅包的人至少搶到一分錢。
下面是算法實現。
package com.bobo.springbootredpacket.util;import com.bobo.springbootredpacket.exception.RedpacketException; import java.util.List; import java.util.Random; import java.util.TreeMap; import java.util.stream.Collectors;public class RedpacketUtil {/*** 分紅包算法:二倍均值法* @param amount 紅包總金額,單位為分* @param total 總人數* @return 隨機金額數組*/public static List<Integer> splitRedpacket(int amount,int total){// 總金額不能小于總人數(即每人至少一分錢),總人數不能少于1人if(amount < total || total < 1){throw new RedpacketException("總金額不能小于總人數(即每人至少一分錢),總人數不能少于1人");}// 隨機金額數組int[] amountArr = new int[total];// 隨機數生成器Random random = new Random();// 剩余金額和剩余人數int residualAmount = amount;int residualTotal = total;// 總共生成total-1個隨機金額for (int i = 0;i < total-1;i++){// 金額除以總人數int max = (residualAmount/residualTotal)*2;// 本次生成的隨機金額,區間:[1,max),不能包含maxint randomAmount = random.nextInt(max-1)+1;amountArr[i] = randomAmount;// 剩余金額減少,剩余人數減1residualAmount -= randomAmount;residualTotal --;}// 為確保紅包正好分完,最后一個人的隨機金額就是剩余金額amountArr[amountArr.length-1] = residualAmount;// 再將生成的隨機金額打散:對每個隨機金額 對應 生成一個隨機數字,然后將這些隨機數字排序TreeMap<Integer, Integer> map = new TreeMap<>();// 表示第i個隨機金額int i = 0;while (map.size() < total){int maxSortNum = random.nextInt(total * 2)+1;if(map.containsKey(maxSortNum)){continue;}map.put(maxSortNum,i);i++;}// 校驗if(map.size() != total){throw new RedpacketException("生成的排序號個數不等于總人數");}// 替換List<Integer> amountList = map.values().stream().map(e -> amountArr[e]).collect(Collectors.toList());return amountList;} }單測:
@Test public void test(){// 100元,10個人分List<Integer> amounts = RedpacketUtil.splitRedpacket(10000, 10);int sum = 0;for (int amount : amounts) {sum += amount;System.out.println((double) amount/100+"元");}System.out.println("搶到的紅包金額之和:"+(double)sum/100+"元"); }單測結果:
12.77元 16.9元 3.08元 11.43元 14.96元 3.85元 6.15元 4.51元 20.07元 6.28元 搶到的紅包金額之和:100.0元總結
以上是生活随笔為你收集整理的高并发抢红包系统红包随机金额生成算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 员工办事指南(社保公积金)
- 下一篇: win7开启ftp被动模式_Win7上防