137 lines
2.9 KiB
Go
137 lines
2.9 KiB
Go
package balancequeue
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
)
|
||
|
||
// 平衡队列
|
||
|
||
type Element interface {
|
||
BalanceQueueHandler()
|
||
}
|
||
|
||
type elementWrapper struct {
|
||
F func()
|
||
}
|
||
|
||
func (e *elementWrapper) BalanceQueueHandler() {
|
||
e.F()
|
||
}
|
||
|
||
func ElementWrapper(f func()) Element {
|
||
return &elementWrapper{F: f}
|
||
}
|
||
|
||
type group struct {
|
||
Array []Element
|
||
queuePos int
|
||
}
|
||
|
||
type groupArray struct {
|
||
queue []*group
|
||
}
|
||
|
||
type BalanceQueue struct {
|
||
index int // 循环索引
|
||
groups []*group // 固定的分组,长度不变,每次Update触发一个分组
|
||
tables []*groupArray
|
||
pool map[Element]*group
|
||
}
|
||
|
||
// New 创建一个平衡队列
|
||
// groupNumber 分组数量
|
||
func New(groupNumber int) *BalanceQueue {
|
||
ret := &BalanceQueue{
|
||
groups: make([]*group, groupNumber),
|
||
tables: make([]*groupArray, 10), // 本身会自动扩容,初始值不是很重要
|
||
pool: make(map[Element]*group),
|
||
}
|
||
|
||
for i := 0; i < len(ret.tables); i++ {
|
||
ret.tables[i] = &groupArray{}
|
||
}
|
||
// 初始化平衡数组,所有平衡队列容量为0
|
||
for i := 0; i < len(ret.groups); i++ {
|
||
ret.groups[i] = &group{queuePos: i}
|
||
ret.tables[0].queue = append(ret.tables[0].queue, ret.groups[i])
|
||
}
|
||
return ret
|
||
}
|
||
|
||
func (q *BalanceQueue) String() string {
|
||
buf := strings.Builder{}
|
||
buf.WriteString("BalanceQueue:\n")
|
||
buf.WriteString(fmt.Sprintf("分组数量: %v\n", len(q.groups)))
|
||
for k, v := range q.tables {
|
||
buf.WriteString(fmt.Sprintf("元素数量%v: 组数量%v ==>", k, len(v.queue)))
|
||
for _, vv := range v.queue {
|
||
buf.WriteString(fmt.Sprintf("%v ", len(vv.Array)))
|
||
}
|
||
buf.WriteString("\n")
|
||
}
|
||
return buf.String()
|
||
}
|
||
|
||
func (q *BalanceQueue) Update() {
|
||
if q.index == len(q.groups) {
|
||
q.index = 0
|
||
}
|
||
for _, v := range q.groups[q.index].Array {
|
||
v.BalanceQueueHandler()
|
||
}
|
||
q.index++
|
||
}
|
||
|
||
func (q *BalanceQueue) Push(e Element) {
|
||
if e == nil {
|
||
return
|
||
}
|
||
|
||
if _, ok := q.pool[e]; ok {
|
||
return
|
||
}
|
||
|
||
for k, v := range q.tables {
|
||
size := len(v.queue)
|
||
if size == 0 {
|
||
continue
|
||
}
|
||
|
||
arr := v.queue[size-1]
|
||
if k+1 >= len(q.tables) {
|
||
q.tables = append(q.tables, &groupArray{})
|
||
}
|
||
q.tables[k+1].queue = append(q.tables[k+1].queue, arr)
|
||
q.tables[k].queue = v.queue[:size-1]
|
||
arr.queuePos = len(q.tables[k+1].queue) - 1
|
||
arr.Array = append(arr.Array, e)
|
||
q.pool[e] = arr
|
||
return
|
||
}
|
||
return
|
||
}
|
||
|
||
func (q *BalanceQueue) Pop(e Element) {
|
||
group, ok := q.pool[e]
|
||
if !ok {
|
||
return
|
||
}
|
||
delete(q.pool, e)
|
||
count := len(group.Array)
|
||
for i := 0; i < count; i++ {
|
||
if group.Array[i] == e {
|
||
group.Array[i] = group.Array[count-1]
|
||
group.Array = group.Array[:count-1]
|
||
bqPos := group.queuePos
|
||
queCount := len(q.tables[count].queue)
|
||
q.tables[count].queue[bqPos] = q.tables[count].queue[queCount-1]
|
||
q.tables[count].queue[bqPos].queuePos = bqPos
|
||
q.tables[count].queue = q.tables[count].queue[:queCount-1]
|
||
q.tables[count-1].queue = append(q.tables[count-1].queue, group)
|
||
group.queuePos = len(q.tables[count-1].queue) - 1
|
||
return
|
||
}
|
||
}
|
||
}
|