我之前的博客中用c語言寫了一個紅包均分算法,用到的數據結構是鏈式數組,今日用堆改進此算法-相較穩定的紅包算法實現/c語言實現,使用的語言是Go語言。
核心算法相同(不瞭解的同學可以點擊上面鏈接閱讀),所以直接上代碼:
//使用堆完成紅包分配算法
package main
import "fmt"
//用於影響分配結果的因子
var yz float32 = 0
type rbHeap struct {
count int
amount float32
heap []float32
}
//值分割算法
func fp(value float32) (va, vb float32) {
yz += 1.0
va, vb = value-yz, yz
return
}
func rbHeapDown(heap []float32, ni int) {
if len(heap) <= 1 {
return
}
hl := len(heap)-1
for {
nl := ni*2+1
nr := ni*2+2
if nl <= hl && nr <= hl{
//與左節點比較, 如果左右節點相等的情況, 左子節點優先進行
if heap[nl]>=heap[nr] && heap[ni]<heap[nl] {
heap[nl], heap[ni] = heap[ni], heap[nl]
ni = nl
continue
//與右節點比較
} else if heap[ni]<heap[nr] {
heap[nr], heap[ni] = heap[ni], heap[nr]
ni = nr
continue
}
} else if nl<=hl && heap[ni]<heap[nl] {
//同末尾節點比較
heap[nl], heap[ni] = heap[ni], heap[nl]
}
break
}
}
func rbHeapUp(heap []float32, ni int) {
if ni <= 0 {
return
}
for ; ni >= 1; {
pi := (ni-1)/2
if heap[ni] > heap[pi] {
heap[ni], heap[pi] = heap[pi], heap[ni]
ni = pi
continue
}
break
}
}
func (rh *rbHeap) heapPush(value float32, root bool) {
if root {
rh.heap[0] = value
rbHeapDown(rh.heap, 0)
} else {
rh.heap = append(rh.heap, value)
rbHeapUp(rh.heap, len(rh.heap)-1)
}
}
func (rh *rbHeap) heapPop() (float32, error) {
if rh.heap != nil && len(rh.heap) > 0 {
return rh.heap[0], nil
}
return 0.0, fmt.Errorf("heap is empty")
}
func processHeap(amount float32, count int) []float32 {
rh := &rbHeap{
count: count,
amount: amount,
heap: make([]float32, 0, count),
}
va, vb := fp(amount)
if va > vb {
rh.heap = append(rh.heap, va)
rh.heap = append(rh.heap, vb)
} else {
rh.heap = append(rh.heap, vb)
rh.heap = append(rh.heap, va)
}
for i := 0; i < count-2; i++ {
v, err := rh.heapPop()
if err != nil {
fmt.Printf("pop error:`%s`\n", err)
break
}
va, vb := fp(v)
rh.heapPush(va, true)
rh.heapPush(vb, false)
}
return rh.heap
}
func main() {
s := time.Now()
result := processHeap(10000000000, 1000000)
_ = result
fmt.Println(time.Since(s).Milliseconds())
}
經過測試,該算法分配100w個紅包的耗時爲ms級別。(大概是因爲分配算法過於簡單吧)