Golang 加權隨機數

什麼是加權隨機數

所謂加權隨機數,即是在隨機數的基礎上進行加權,每個元素的出現概率不是均等的。例如{'a': 2, 'b': 3, 'c': 5}, 那麼a 出現的概率爲20%,b出現的概率爲30%, c 出現的概率爲50%。

爲什麼需要加權隨機數

對我而言,主要應用於一些線上抽獎活動,每個獎品出現的概率不能是均等的。所以要加權。

Golang 的支持

在github 搜索了一下,發現了有一個包。https://github.com/mroth/weightedrand 地址是這個。源碼非常的精短,因爲這個東西並不複雜。一般來說實現思路爲:按出現頻次生成一個數組,如上訴例子則爲[a, a, b, b, b, c, c, c, c, c],然後將數組打亂獲取需要的隨機數。但這個有個問題就是數組大小等於總頻次大小,一旦頻次非常大,這個就會非常佔內存。weightedrand 給出另外一個方案,利用二分法來獲取隨機數。以下是源碼

package weightedrand

import (
	"math/rand"
	"sort"
)

// Choice is a generic wrapper that can be used to add weights for any object
type Choice struct {
	Item   interface{}
	Weight uint
}

// A Chooser caches many possible Choices in a structure designed to improve
// performance on repeated calls for weighted random selection.
type Chooser struct {
	data   []Choice
	totals []int
	max    int
}

// NewChooser initializes a new Chooser consisting of the possible Choices.
func NewChooser(cs ...Choice) Chooser {
	sort.Slice(cs, func(i, j int) bool {
		return cs[i].Weight < cs[j].Weight
	})// 核心點,對元素進行遞增排序。
	totals := make([]int, len(cs))
	runningTotal := 0
	for i, c := range cs {
		runningTotal += int(c.Weight)
		totals[i] = runningTotal
	}
	return Chooser{data: cs, totals: totals, max: runningTotal}
}

// Pick returns a single weighted random Choice.Item from the Chooser.
func (chs Chooser) Pick() interface{} {
	r := rand.Intn(chs.max) + 1 // 使用最大值獲取隨機數,避免超過範圍,隨機生成的數需要排除0,故加1
	i := sort.SearchInts(chs.totals, r) // 核心點該方法使用二分法,找到對應的下標,如果沒有則爲大於該數的+1 下標,可能爲len(a)即數組長度。
	return chs.data[i].Item
}

i := sort.SearchInts(chs.totals, r) // 核心點該方法使用二分法,找到對應的下標,如果沒有則爲大於該數的+1 下標,可能爲len(a)即數組長度。如上訴例子,按該方法則會生成數組[0, 2, 5, 10],則隨機數1, 2 爲數組下標1, 隨機數3,4,5爲數組下標2。相當於隨機數1,2 爲a,同理隨機數3,4,5 則爲b,6,7,8,9,10 則爲c。通過該方法比原來方法更節約內存空間,也減少了隨機數計算。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章