92 lines
2.1 KiB
Go
92 lines
2.1 KiB
Go
package ds
|
|
|
|
// ds-set.go
|
|
// 泛型集合,基于 map[T]struct{}。T 约束为 comparable。
|
|
// Add/Remove/Contains 均 O(1) 均摊。支持并集/交集/差集。
|
|
// 比 map[T]bool 更省内存(空结构体不占空间),语义也更清晰。
|
|
|
|
// Set 泛型集合,零值不可直接用(map 零值不能写),必须用 NewSet。
|
|
type Set[T comparable] struct {
|
|
m map[T]struct{}
|
|
}
|
|
|
|
// NewSet 创建空集合。
|
|
func NewSet[T comparable]() *Set[T] {
|
|
return &Set[T]{m: make(map[T]struct{})}
|
|
}
|
|
|
|
// NewSetFrom 从切片创建集合,自动去重。
|
|
func NewSetFrom[T comparable](vals []T) *Set[T] {
|
|
s := NewSet[T]()
|
|
for _, v := range vals {
|
|
s.m[v] = struct{}{}
|
|
}
|
|
return s
|
|
}
|
|
|
|
// Add 添加元素,已存在则无操作。
|
|
func (s *Set[T]) Add(v T) { s.m[v] = struct{}{} }
|
|
|
|
// Remove 删除元素,不存在则无操作。
|
|
func (s *Set[T]) Remove(v T) { delete(s.m, v) }
|
|
|
|
// Contains 是否包含元素。
|
|
func (s *Set[T]) Contains(v T) bool {
|
|
_, ok := s.m[v]
|
|
return ok
|
|
}
|
|
|
|
// Len 元素个数。
|
|
func (s *Set[T]) Len() int { return len(s.m) }
|
|
|
|
// Empty 是否为空。
|
|
func (s *Set[T]) Empty() bool { return len(s.m) == 0 }
|
|
|
|
// ToSlice 转为切片。map 遍历顺序无序,如需稳定顺序需自行排序。
|
|
func (s *Set[T]) ToSlice() []T {
|
|
out := make([]T, 0, len(s.m))
|
|
for v := range s.m {
|
|
out = append(out, v)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// Union 并集:返回新集合,包含 s 和 other 的所有元素。
|
|
func (s *Set[T]) Union(other *Set[T]) *Set[T] {
|
|
r := NewSet[T]()
|
|
for v := range s.m {
|
|
r.m[v] = struct{}{}
|
|
}
|
|
for v := range other.m {
|
|
r.m[v] = struct{}{}
|
|
}
|
|
return r
|
|
}
|
|
|
|
// Intersect 交集:返回新集合,仅包含 s 和 other 都有的元素。
|
|
func (s *Set[T]) Intersect(other *Set[T]) *Set[T] {
|
|
r := NewSet[T]()
|
|
// 遍历较小集合,降低常数
|
|
small, big := s, other
|
|
if small.Len() > big.Len() {
|
|
small, big = big, small
|
|
}
|
|
for v := range small.m {
|
|
if _, ok := big.m[v]; ok {
|
|
r.m[v] = struct{}{}
|
|
}
|
|
}
|
|
return r
|
|
}
|
|
|
|
// Difference 差集:返回新集合,包含在 s 中但不在 other 中的元素。
|
|
func (s *Set[T]) Difference(other *Set[T]) *Set[T] {
|
|
r := NewSet[T]()
|
|
for v := range s.m {
|
|
if _, ok := other.m[v]; !ok {
|
|
r.m[v] = struct{}{}
|
|
}
|
|
}
|
|
return r
|
|
}
|