Skip to content

feat(container/gtree): Add the function of popping left and right nodes of red-black tree - #4793

Open
LanceAdd wants to merge 5 commits into
gogf:masterfrom
LanceAdd:canzhao
Open

feat(container/gtree): Add the function of popping left and right nodes of red-black tree#4793
LanceAdd wants to merge 5 commits into
gogf:masterfrom
LanceAdd:canzhao

Conversation

@LanceAdd

Copy link
Copy Markdown
Member

摘要

RedBlackKVTree(泛型)和 RedBlackTree(非泛型)新增 PopLeftPopRight 方法,支持原子地弹出最小和最大节点。

动机

现有的 Left/Right 方法只能查看极值节点,删除需要再调用 Remove(node.Key)。这两步之间存在竞争窗口:

// 之前:两步操作,非原子
node := m.Left()
v := m.Remove(node.Key)

// 之后:一步操作,原子
node := m.PopLeft()

该模式与 garray.PopLeft/garray.PopRight 保持一致,使 RedBlackKVTree 可以作为并发安全的优先级队列使用,替代 container/heap 且具有更好的类型安全。

实现

两个方法在内部持有写锁,并直接操作底层数据结构,避免调用公开的 Left/Right(会重复加锁导致死锁):

func (tree *RedBlackKVTree[K, V]) PopLeft() *RedBlackKVTreeNode[K, V] {
    tree.mu.Lock()
    defer tree.mu.Unlock()
    node := tree.tree.Left()     // gods 库原生 Left,不经过 GoFrame 锁
    if node == nil { return nil }
    tree.doRemove(node.Key)      // 内部无锁方法
    return &RedBlackKVTreeNode[K, V]{...}
}

变更文件

文件 变更内容
container/gtree/gtree_k_v_redblacktree.go 新增泛型版 PopLeftPopRight
container/gtree/gtree_redblacktree.go 新增非泛型版,委托至泛型实现

示例

m := gtree.NewRedBlackKVTree[int, string](gutil.ComparatorT[int], true)
m.Set(3, "c")
m.Set(1, "a")
m.Set(2, "b")

node := m.PopLeft()  // {1, "a"}, O(log n), 原子操作
node = m.PopLeft()   // {2, "b"}
node = m.PopRight()  // {3, "c"}

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds atomic “pop” operations to GoFrame’s red-black tree containers (container/gtree), enabling callers to remove-and-return the current minimum/maximum element in a single concurrency-safe operation (aligning with garray.PopLeft/PopRight usage patterns).

Changes:

  • Add PopLeft/PopRight to RedBlackKVTree[K,V], removing and returning min/max nodes under a write lock.
  • Add PopLeft/PopRight to non-generic RedBlackTree, delegating to the generic implementation after lazyInit().

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
container/gtree/gtree_k_v_redblacktree.go Implements PopLeft/PopRight on the generic red-black tree with write locking and internal removal.
container/gtree/gtree_redblacktree.go Adds non-generic PopLeft/PopRight wrappers delegating to the generic tree after lazy initialization.
Comments suppressed due to low confidence (1)

container/gtree/gtree_k_v_redblacktree.go:548

  • PopRight already has the right-most node (including its Value), but calling doRemove(node.Key) does an extra tree.Get before removing. This adds an extra O(log n) lookup on every pop; you can remove the key directly here since the value is already known.
	node := tree.tree.Right()
	if node == nil {
		return nil
	}
	tree.doRemove(node.Key)
	return &RedBlackKVTreeNode[K, V]{
		Key:   node.Key,
		Value: node.Value,
	}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread container/gtree/gtree_k_v_redblacktree.go
Comment thread container/gtree/gtree_k_v_redblacktree.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants