mirror of
https://github.com/metabarcoding/obitools4.git
synced 2025-12-08 00:30:27 +00:00
implementation de obilowmask
This commit is contained in:
118
pkg/obiutils/minmultiset.go
Normal file
118
pkg/obiutils/minmultiset.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package obiutils
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
)
|
||||
|
||||
// MinMultiset maintient un multiset de valeurs et expose le minimum courant.
|
||||
// T doit être comparable pour servir de clé de map. L'ordre est défini par less.
|
||||
type MinMultiset[T comparable] struct {
|
||||
pq priorityQueue[T] // tas min
|
||||
less func(a, b T) bool
|
||||
count map[T]int // cardinalité logique par valeur
|
||||
pending map[T]int // suppressions en attente (lazy delete)
|
||||
size int // taille logique totale
|
||||
}
|
||||
|
||||
// New crée un multiset. less doit imposer un ordre strict total.
|
||||
func NewMinMultiset[T comparable](less func(a, b T) bool) *MinMultiset[T] {
|
||||
m := &MinMultiset[T]{
|
||||
pq: priorityQueue[T]{less: less},
|
||||
less: less,
|
||||
count: make(map[T]int),
|
||||
pending: make(map[T]int),
|
||||
}
|
||||
heap.Init(&m.pq)
|
||||
return m
|
||||
}
|
||||
|
||||
// Add ajoute une occurrence.
|
||||
func (m *MinMultiset[T]) Add(v T) {
|
||||
heap.Push(&m.pq, v)
|
||||
m.count[v]++
|
||||
m.size++
|
||||
}
|
||||
|
||||
// RemoveOne retire UNE occurrence de v. Retourne false si absente.
|
||||
func (m *MinMultiset[T]) RemoveOne(v T) bool {
|
||||
if m.count[v] == 0 {
|
||||
return false
|
||||
}
|
||||
m.count[v]--
|
||||
m.pending[v]++
|
||||
m.size--
|
||||
m.shrink()
|
||||
return true
|
||||
}
|
||||
|
||||
// Min retourne le minimum courant. ok=false si vide.
|
||||
func (m *MinMultiset[T]) Min() (v T, ok bool) {
|
||||
if m.size == 0 {
|
||||
var zero T
|
||||
return zero, false
|
||||
}
|
||||
m.cleanTop()
|
||||
return m.pq.data[0], true
|
||||
}
|
||||
|
||||
// Len retourne la taille logique.
|
||||
func (m *MinMultiset[T]) Len() int { return m.size }
|
||||
|
||||
// --- interne ---
|
||||
|
||||
// retire du sommet toutes les valeurs marquées à supprimer.
|
||||
func (m *MinMultiset[T]) cleanTop() {
|
||||
for m.pq.Len() > 0 {
|
||||
top := m.pq.data[0]
|
||||
if m.pending[top] > 0 {
|
||||
m.pending[top]--
|
||||
if m.pending[top] == 0 {
|
||||
delete(m.pending, top) // ← nettoyage de la map
|
||||
}
|
||||
heap.Pop(&m.pq)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// rééquilibre le tas si trop de tombstones.
|
||||
func (m *MinMultiset[T]) shrink() {
|
||||
// nettoyage léger au retrait pour borner la dérive
|
||||
if m.pq.Len() > 0 {
|
||||
m.cleanTop()
|
||||
}
|
||||
}
|
||||
|
||||
// priorityQueue implémente heap.Interface pour T.
|
||||
type priorityQueue[T any] struct {
|
||||
data []T
|
||||
less func(a, b T) bool
|
||||
}
|
||||
|
||||
func (q priorityQueue[T]) Len() int { return len(q.data) }
|
||||
func (q priorityQueue[T]) Less(i, j int) bool { return q.less(q.data[i], q.data[j]) }
|
||||
func (q priorityQueue[T]) Swap(i, j int) { q.data[i], q.data[j] = q.data[j], q.data[i] }
|
||||
func (q *priorityQueue[T]) Push(x any) { q.data = append(q.data, x.(T)) }
|
||||
func (q *priorityQueue[T]) Pop() any {
|
||||
n := len(q.data)
|
||||
x := q.data[n-1]
|
||||
q.data = q.data[:n-1]
|
||||
return x
|
||||
}
|
||||
func (q priorityQueue[T]) peek() (T, bool) {
|
||||
if len(q.data) == 0 {
|
||||
var z T
|
||||
return z, false
|
||||
}
|
||||
return q.data[0], true
|
||||
}
|
||||
func (q *priorityQueue[T]) Top() (T, bool) { return q.peek() }
|
||||
func (q *priorityQueue[T]) PushValue(v T) { heap.Push(q, v) }
|
||||
func (q *priorityQueue[T]) PopValue() (T, bool) {
|
||||
if q.Len() == 0 {
|
||||
var z T
|
||||
return z, false
|
||||
}
|
||||
return heap.Pop(q).(T), true
|
||||
}
|
||||
Reference in New Issue
Block a user