zset

package
v0.4.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 18, 2026 License: MIT Imports: 4 Imported by: 0

README

ZSet

纯 Go 的成员索引与带排名跨度的跳表,支持 Windows、Linux、macOS,普通构建无需 CGo 或 C 编译器。导入路径和包名保留为 github.com/NumberMan1/numbox/pkg/go-zset / zset。

z := zset.New()
z.Add(100, "alice")
z.Add(100, "bob")
z.Add(80, "carol")
rank := z.Rank("alice")       // 2
top := z.RevRange(1, 2)        // ["bob", "alice"]
removed := z.RevLimit(2)       // 1,保留最大的两项

排序与范围

  • 按 float64 分数升序,再按成员字符串的字节序升序。同分排名不共享,每个成员有独立排名。
  • Add 更新已有成员的分数,不增加数量;同分更新不改变位置。支持空字符串、Unicode 和含 NUL 的成员。
  • Rank / RevRank 从 1 开始,不存在返回 0。Score 返回分数与存在标志。
  • Range / RevRange 的两端均包含,排名从 1 开始,端点逆序则反向遍历,不支持负数排名。 起点越界返回空结果,尾端越界截断;大端点不会导致按该端点大小分配内存。
  • RangeByScore 是包含边界的分数区间,起始分数大于结束分数时降序,等分区间返回成员升序。
  • Limit 保留最小的 count 项,RevLimit 保留最大的 count 项;返回实际删除数量。 count<=0 清空集合。
  • 分数允许正负无穷;Add 遇到 NaN 会在修改前 panic。RangeByScore 遇到 NaN 边界返回空切片。
  • float64 的精度限制保持不变。Dump 只用于诊断,不承诺固定输出格式。

并发与复杂度

零值可直接使用,使用后不可复制。所有公开方法均受实例 RWMutex 保护;每次查询及整个 裁剪操作具有一致状态。多个方法调用之间不是事务,跨调用的结果可能被其他协程更新。 返回的成员切片由调用方持有,不借出内部节点。

成员查分、计数为 O(1);添加、更新、删除和排名预期 O(log N);范围查询及批量裁剪 预期 O(log N + K),K 为返回/删除项数。更新分数复用原节点与层数组,不额外分配节点。 新成员的跳表层数按 1/4 概率提升,最多 32 层,不使用反射或外部数据结构依赖。

验证

CGO_ENABLED=0 go test ./pkg/go-zset
go test -race ./pkg/go-zset
go test ./pkg/go-zset -run '^$' -fuzz FuzzPureGoOperations -fuzztime=10s
go test ./pkg/go-zset -run '^$' -bench BenchmarkPureGoZSet -benchmem

测试包含排序 Map 对照、每层跨度与反向链校验、随机更新/删除/裁剪和并发读写。 本实现没有 C 内存与 finalizer,生命周期由 Go GC 管理。竞态检测本身仍受 Go 工具链的 CGo 要求约束。

2026-10-18 本地基准:Windows/amd64、Ryzen 7 5800H、10,000 个成员, CGO_ENABLED=0 -cpu=1 -benchtime=300ms -count=3,下表为三次测量中位数。

操作 ns/op B/op allocs/op
排名查询 135.7 0 0
已有成员更新分数 330.0 0 0
返回 20 个连续排名成员 479.7 320 1

与旧 CGo 实现的同场景对照、分配及进程内存实验见 性能对比。

Documentation

Overview

Package zset provides a concurrent, ranked sorted set implemented in pure Go.

Index

Constants

View Source
const DEFAULT_TBL_LEN = 16

DEFAULT_TBL_LEN is the initial member-index capacity, retained for compatibility.

Variables

This section is empty.

Functions

This section is empty.

Types

type ZSet

type ZSet struct {
	// contains filtered or unexported fields
}

ZSet sorts by score ascending, then member bytes ascending. Methods are safe concurrently; each query and trim observes one locked state. The zero value works. Do not copy a ZSet after first use.

func New

func New() *ZSet

New creates an empty set. No C compiler, finalizer or explicit Close is needed.

func (*ZSet) Add

func (z *ZSet) Add(score float64, member string)

Add inserts a member or updates its score. NaN panics before changing the set; infinities are supported. Updating a member reuses its allocated node/tower.

func (*ZSet) Count

func (z *ZSet) Count() int

Count returns the number of members.

func (*ZSet) Dump

func (z *ZSet) Dump()

Dump prints a diagnostic snapshot to stdout. The text format is not an API.

func (*ZSet) Limit

func (z *ZSet) Limit(count int) int

Limit retains the lowest count members, returning the number removed. A negative count is treated as zero. The entire trim is atomic.

func (*ZSet) Range

func (z *ZSet) Range(first, last int) []string

Range returns an inclusive, 1-based rank range. first>last walks backwards from first. Nonpositive ranks return nil; an out-of-set first returns empty. Endpoints beyond the end are bounded without allocating for the excess range.

func (*ZSet) RangeByScore

func (z *ZSet) RangeByScore(first, last float64) []string

RangeByScore returns the inclusive score range, descending when first>last. NaN bounds return an empty slice. Equal scores are ordered by member bytes.

func (*ZSet) Rank

func (z *ZSet) Rank(member string) int

Rank returns the member's 1-based ascending rank, or zero when absent.

func (*ZSet) Rem

func (z *ZSet) Rem(member string)

Rem removes a member, doing nothing if it is absent.

func (*ZSet) RevLimit

func (z *ZSet) RevLimit(count int) int

RevLimit retains the highest count members, returning the number removed. A negative count is treated as zero. The entire trim is atomic.

func (*ZSet) RevRange

func (z *ZSet) RevRange(first, last int) []string

RevRange uses 1-based ranks counted from the largest member. An end beyond Count is clamped. Reversing the endpoints reverses traversal direction.

func (*ZSet) RevRank

func (z *ZSet) RevRank(member string) int

RevRank returns the member's 1-based descending rank, or zero when absent.

func (*ZSet) Score

func (z *ZSet) Score(member string) (float64, bool)

Score returns a member's score and whether it exists.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL