codeforces-go中的平衡树:Treap实现细节

codeforces-go中的平衡树:Treap实现细节

【免费下载链接】codeforces-go 算法竞赛模板库 by 灵茶山艾府 💭💡🎈 【免费下载链接】codeforces-go 项目地址: https://gitcode.com/GitHub_Trending/co/codeforces-go

Treap(树堆)是一种结合了二叉搜索树(BST)和堆(Heap)特性的数据结构,通过随机化优先级维护树的平衡。在codeforces-go项目中,Treap的实现位于copypasta/treap.go,其核心设计融合了BST的有序性与堆的堆序性,确保操作复杂度为O(log n)。

数据结构定义

Treap节点结构包含左右子树指针、优先级、子树大小及键值对信息:

type tpNode struct {
    lr       [2]*tpNode  // 左右子树,0表示左,1表示右
    priority uint        // 最大堆优先级
    sz       int         // 子树大小
    msz      int         // 多集大小(含重复元素计数)
    key      tpKeyType   // 键
    val      tpValueType // 值(用于多集计数)
}

节点优先级通过随机数生成,确保树结构在概率意义上平衡。子树大小维护通过maintain方法实现:

func (o *tpNode) maintain() {
    o.sz = 1 + o.lr[0].size() + o.lr[1].size()
    o.msz = int(o.val) + o.lr[0].mSize() + o.lr[1].mSize()
}

核心操作实现

旋转操作

旋转是维持Treap平衡的关键,分为左旋和右旋:

// d=0:左旋,返回o的右儿子;d=1:右旋,返回o的左儿子
func (o *tpNode) rotate(d int) *tpNode {
    x := o.lr[d^1]
    o.lr[d^1] = x.lr[d]
    x.lr[d] = o
    o.maintain()
    x.maintain()
    return x
}

左旋将右子树提升为新根,右旋将左子树提升为新根,旋转后需重新维护子树大小。

插入操作

插入流程遵循BST规则,插入后通过旋转调整以满足堆优先级:

func (t *treap) _put(o *tpNode, key tpKeyType, val tpValueType) *tpNode {
    if o == nil {
        return &tpNode{priority: t.fastRand(), sz: 1, msz: 1, key: key, val: val}
    }
    if d := o.cmp(key); d >= 0 { // 0:左子树,1:右子树
        o.lr[d] = t._put(o.lr[d], key, val)
        if o.lr[d].priority > o.priority { // 子节点优先级更高,触发旋转
            o = o.rotate(d ^ 1) // 左子树右旋(d=0→d^1=1),右子树左旋(d=1→d^1=0)
        }
    } else {
        o.val += val // 键已存在,更新值(支持重复元素)
    }
    o.maintain()
    return o
}

删除操作

删除通过将目标节点旋转至叶节点后移除,过程中始终保持堆优先级:

func (t *treap) _delete(o *tpNode, key tpKeyType) *tpNode {
    if o == nil {
        return nil
    }
    if d := o.cmp(key); d >= 0 {
        o.lr[d] = t._delete(o.lr[d], key)
    } else {
        if o.val > 1 { // 多集删除,减少计数
            o.val--
        } else { // 叶节点删除
            if o.lr[1] == nil {
                return o.lr[0]
            }
            if o.lr[0] == nil {
                return o.lr[1]
            }
            // 选择优先级高的子树旋转至根
            d = 0
            if o.lr[0].priority > o.lr[1].priority {
                d = 1
            }
            o = o.rotate(d)
            o.lr[d] = t._delete(o.lr[d], key)
        }
    }
    o.maintain()
    return o
}

与笛卡尔树的关联

Treap本质上属于笛卡尔树(Cartesian Tree)的一种变体,笛卡尔树的实现可见copypasta/cartesian_tree.go。两者均通过键值与优先级(或权值)构建树结构,但Treap的优先级为随机生成,而笛卡尔树通常基于数组元素值。

可视化功能

Treap提供树形打印功能,以逆时针90°方向展示结构:

func (t *treap) String() string {
    if t.root == nil {
        return "Empty\n"
    }
    treeSB := &strings.Builder{}
    treeSB.WriteString("Root\n")
    t.root.draw(treeSB, &strings.Builder{}, true)
    return treeSB.String()
}

示例输出:

Root
└── 62[sz:...,msz:...
    ├── 90[sz:...,msz:...
    │   ├── 66[sz:...,msz:...
    │   │   └── 74[sz:...,msz:...
    │   └── 94[sz:...,msz:...
    └── 40[sz:...,msz:...
        └── 25[sz:...,msz:...

泛型版本与扩展

代码中包含泛型占位实现(treapM),支持自定义比较器:

type treapM[K comparable, V any] struct {
    rd         uint
    root       *nodeM[K, V]
    comparator func(a, b K) int // 自定义比较器
}

完整泛型实现可参考copypasta/treap/目录,支持有序映射、集合等扩展功能。

应用场景

Treap适用于需要高效插入、删除和查询的数据场景,如:

  • 动态有序序列维护
  • 区间查询与排名统计
  • 离线算法中的数据结构支撑

项目中相关题目参考:

通过结合BST与堆的特性,Treap在codeforces-go中提供了可靠的平衡树实现,为算法竞赛中的复杂数据处理需求提供高效支持。

【免费下载链接】codeforces-go 算法竞赛模板库 by 灵茶山艾府 💭💡🎈 【免费下载链接】codeforces-go 项目地址: https://gitcode.com/GitHub_Trending/co/codeforces-go

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值