304 lines
8.9 KiB
Go
Raw Normal View History

package treap
//@Title Treap
//@Description
// 树堆的节点
// 节点在创建是赋予一个随机的优先级,随后进行堆平衡,使得整个树堆依概率实现平衡
// 可通过节点实现树堆的添加删除
// 也可通过节点返回整个二叉搜索树的所有元素
import (
"github.com/hlccd/goSTL/utils/comparator"
"math/rand"
)
//node树节点结构体
//该节点是树堆的树节点
//若该树堆允许重复则对节点num+1即可,否则对value进行覆盖
//树堆节点将针对堆的性质通过左右旋转的方式做平衡
type node struct {
value interface{} //节点中存储的元素
priority uint32 //该节点的优先级,随机生成
num int //该节点中存储的数量
left *node //左节点指针
right *node //右节点指针
}
//@title newNode
//@description
// 新建一个树堆节点并返回
// 将传入的元素e作为该节点的承载元素
// 该节点的num默认为1,左右子节点设为nil
// 该节点优先级随机生成,范围在0~2^16内
//@receiver nil
//@param e interface{} 承载元素e
//@param rand *rand.Rand 随机数生成器
//@return n *node 新建的树堆树节点的指针
func newNode(e interface{}, rand *rand.Rand) (n *node) {
return &node{
value: e,
priority: uint32(rand.Intn(4294967295)),
num: 1,
left: nil,
right: nil,
}
}
//@title inOrder
//@description
// 以node树堆节点做接收者
// 以中缀序列返回节点集合
// 若允许重复存储则对于重复元素进行多次放入
//@receiver n *node 接受者node的指针
//@param nil
//@return es []interface{} 以该节点为起点的中缀序列
func (n *node) inOrder() (es []interface{}) {
if n == nil {
return es
}
if n.left != nil {
es = append(es, n.left.inOrder()...)
}
for i := 0; i < n.num; i++ {
es = append(es, n.value)
}
if n.right != nil {
es = append(es, n.right.inOrder()...)
}
return es
}
//@title rightRotate
//@description
// 以node树堆节点做接收者
// 新建一个节点作为n节点的右节点,同时将n节点的数值放入新建节点中作为右转后的n节点
// 右转后的n节点的左节点是原n节点左节点的右节点,右转后的右节点保持不变
// 原n节点改为原n节点的左节点,同时右节点指向新建的节点即右转后的n节点
// 该右转方式可以保证n节点的双亲节点不用更换节点指向
//@receiver n *node 接受者node的指针
//@param nil
//@return nil
func (n *node) rightRotate() {
if n == nil {
return
}
if n.left == nil {
return
}
//新建节点作为更换后的n节点
tmp := &node{
value: n.value,
priority: n.priority,
num: n.num,
left: n.left.right,
right: n.right,
}
//原n节点左节点上移到n节点位置
n.right = tmp
n.value = n.left.value
n.priority = n.left.priority
n.num = n.left.num
n.left = n.left.left
}
//@title leftRotate
//@description
// 以node树堆节点做接收者
// 新建一个节点作为n节点的左节点,同时将n节点的数值放入新建节点中作为左转后的n节点
// 左转后的n节点的右节点是原n节点右节点的左节点,左转后的左节点保持不变
// 原n节点改为原n节点的右节点,同时左节点指向新建的节点即左转后的n节点
// 该左转方式可以保证n节点的双亲节点不用更换节点指向
//@receiver n *node 接受者node的指针
//@param nil
//@return nil
func (n *node) leftRotate() {
if n == nil {
return
}
if n.right == nil {
return
}
//新建节点作为更换后的n节点
tmp := &node{
value: n.value,
priority: n.priority,
num: n.num,
left: n.left,
right: n.right.left,
}
//原n节点右节点上移到n节点位置
n.left = tmp
n.value = n.right.value
n.priority = n.right.priority
n.num = n.right.num
n.right = n.right.right
}
//@title insert
//@description
// 以node二叉搜索树节点做接收者
// 从n节点中插入元素e
// 如果n节点中承载元素与e不同则根据大小从左右子树插入该元素
// 如果n节点与该元素相等,且允许重复值,则将num+1否则对value进行覆盖
// 插入成功返回true,插入失败或不允许重复插入返回false
//@receiver n *node 接受者node的指针
//@param e interface{} 待插入元素
//@param isMulti bool 是否允许重复?
//@param cmp comparator.Comparator 判断大小的比较器
//@return b bool 是否插入成功?
func (n *node) insert(e *node, isMulti bool, cmp comparator.Comparator) (b bool) {
if cmp(n.value, e.value) > 0 {
if n.left == nil {
//将左节点直接设为e
n.left = e
b = true
} else {
//对左节点进行递归插入
b = n.left.insert(e, isMulti, cmp)
}
if n.priority > e.priority {
//对n节点进行右转
n.rightRotate()
}
return b
} else if cmp(n.value, e.value) < 0 {
if n.right == nil {
//将右节点直接设为e
n.right = e
b = true
} else {
//对右节点进行递归插入
b = n.right.insert(e, isMulti, cmp)
}
if n.priority > e.priority {
//对n节点进行左转
n.leftRotate()
}
return b
}
if isMulti {
//允许重复
n.num++
return true
}
//不允许重复,对值进行覆盖
n.value = e.value
return false
}
//@title delete
//@description
// 以node二叉搜索树节点做接收者
// 从n节点中删除元素e
// 如果n节点中承载元素与e不同则根据大小从左右子树删除该元素
// 如果n节点与该元素相等,且允许重复值,则将num-1否则直接删除该元素
// 删除时先寻找该元素的前缀节点,若不存在则寻找其后继节点进行替换
// 替换后删除该节点
//@receiver n *node 接受者node的指针
//@param e interface{} 待删除元素
//@param isMulti bool 是否允许重复?
//@param cmp comparator.Comparator 判断大小的比较器
//@return b bool 是否删除成功?
func (n *node) delete(e interface{}, isMulti bool, cmp comparator.Comparator) (b bool) {
if n == nil {
return false
}
//n中承载元素小于e,从右子树继续删除
if cmp(n.value, e) < 0 {
if n.right == nil {
//右子树为nil,删除终止
return false
}
if cmp(e, n.right.value) == 0 && (!isMulti || n.right.num == 1) {
//待删除节点无子节点,直接删除即可
if n.right.left == nil && n.right.right == nil {
//右子树可直接删除
n.right = nil
return true
}
}
//从右子树继续删除
return n.right.delete(e, isMulti, cmp)
}
//n中承载元素大于e,从左子树继续删除
if cmp(n.value, e) > 0 {
if n.left == nil {
//左子树为nil,删除终止
return false
}
if cmp(e, n.left.value) == 0 && (!isMulti || n.left.num == 1) {
//待删除节点无子节点,直接删除即可
if n.left.left == nil && n.left.right == nil {
//左子树可直接删除
n.left = nil
return true
}
}
//从左子树继续删除
return n.left.delete(e, isMulti, cmp)
}
if isMulti && n.num > 1 {
//允许重复且数量超过1
n.num--
return true
}
//删除该节点
tmp := n
//左右子节点都存在则选择优先级较小一个进行旋转
for tmp.left != nil && tmp.right != nil {
if tmp.left.priority < tmp.right.priority {
tmp.rightRotate()
if tmp.right.left == nil && tmp.right.right == nil {
tmp.right = nil
return false
}
tmp = tmp.right
} else {
tmp.leftRotate()
if tmp.left.left == nil && tmp.left.right == nil {
tmp.left = nil
return false
}
tmp = tmp.left
}
}
if tmp.left == nil && tmp.right != nil {
//到左子树为nil时直接换为右子树即可
tmp.value = tmp.right.value
tmp.num = tmp.right.num
tmp.priority = tmp.right.priority
tmp.left = tmp.right.left
tmp.right = tmp.right.right
} else if tmp.right == nil && tmp.left != nil {
//到右子树为nil时直接换为左子树即可
tmp.value = tmp.left.value
tmp.num = tmp.left.num
tmp.priority = tmp.left.priority
tmp.right = tmp.left.right
tmp.left = tmp.left.left
}
//当左右子树都为nil时直接结束
return true
}
//@title search
//@description
// 以node二叉搜索树节点做接收者
// 从n节点中查找元素e并返回存储的个数
// 如果n节点中承载元素与e不同则根据大小从左右子树查找该元素
// 如果n节点与该元素相等,则直接返回其个数
//@receiver n *node 接受者node的指针
//@param e interface{} 待查找元素
//@param isMulti bool 是否允许重复?
//@param cmp comparator.Comparator 判断大小的比较器
//@return num int 待查找元素在二叉树中存储的数量
func (n *node) search(e interface{}, cmp comparator.Comparator) (num int) {
if n == nil {
return 0
}
if cmp(n.value, e) > 0 {
return n.left.search(e, cmp)
} else if cmp(n.value, e) < 0 {
return n.right.search(e, cmp)
}
return n.num
}