mirror of
https://github.com/hlccd/goSTL.git
synced 2025-10-03 02:15:34 +08:00
将所有文件的目录结构进行调整,以保证使用者下载即可用
This commit is contained in:
304
data_structure/treap/node.go
Normal file
304
data_structure/treap/node.go
Normal file
@@ -0,0 +1,304 @@
|
||||
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
|
||||
}
|
242
data_structure/treap/treap.go
Normal file
242
data_structure/treap/treap.go
Normal file
@@ -0,0 +1,242 @@
|
||||
package treap
|
||||
|
||||
//@Title treap
|
||||
//@Description
|
||||
// Treap树堆容器包
|
||||
// 树堆本身是一个二叉树,同时赋予随机的节点优先级
|
||||
// 通过旋转使树堆中节点既满足存储元素的组成符合二叉搜索树的性质,同时也使得优先级满足堆的的性质
|
||||
// 同时由于每个节点的优先级随机生成,使得整个二叉树得以实现随机平衡
|
||||
// 该树堆依概率实现平衡
|
||||
// 可接纳不同类型的元素,但建议在同一个树堆中使用相同类型的元素
|
||||
// 配合比较器实现元素之间的大小比较
|
||||
|
||||
import (
|
||||
"github.com/hlccd/goSTL/utils/comparator"
|
||||
"github.com/hlccd/goSTL/utils/iterator"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
//treap树堆结构体
|
||||
//该实例存储树堆的根节点
|
||||
//同时保存该树堆中已经存储了多少个元素
|
||||
//二叉树中排序使用的比较器在创建时传入,若不传入则在插入首个节点时从默认比较器中寻找
|
||||
//该树堆实例中存储随机数生成器,用于后续新建节点时生成随机数
|
||||
//创建时传入是否允许该树堆出现重复值,如果不允许则进行覆盖,允许则对节点数目增加即可
|
||||
type treap struct {
|
||||
root *node //根节点指针
|
||||
size int //存储元素数量
|
||||
cmp comparator.Comparator //比较器
|
||||
rand *rand.Rand //随机数生成器
|
||||
isMulti bool //是否允许重复
|
||||
mutex sync.Mutex //并发控制锁
|
||||
}
|
||||
|
||||
//treap树堆容器接口
|
||||
//存放了treap树堆可使用的函数
|
||||
//对应函数介绍见下方
|
||||
type treaper interface {
|
||||
Iterator() (i *Iterator.Iterator) //返回包含该树堆的所有元素,重复则返回多个
|
||||
Size() (num int) //返回该树堆中保存的元素个数
|
||||
Clear() //清空该树堆
|
||||
Empty() (b bool) //判断该树堆是否为空
|
||||
Insert(e interface{}) //向树堆中插入元素e
|
||||
Erase(e interface{}) //从树堆中删除元素e
|
||||
Count(e interface{}) (num int) //从树堆中寻找元素e并返回其个数
|
||||
}
|
||||
|
||||
//@title New
|
||||
//@description
|
||||
// 新建一个treap树堆容器并返回
|
||||
// 初始根节点为nil
|
||||
// 传入该树堆是否为可重复属性,如果为true则保存重复值,否则对原有相等元素进行覆盖
|
||||
// 若有传入的比较器,则将传入的第一个比较器设为该树堆的比较器
|
||||
//@receiver nil
|
||||
//@param isMulti bool 该树堆是否保存重复值?
|
||||
//@param Cmp ...comparator.Comparator treap比较器集
|
||||
//@return t *treap 新建的treap指针
|
||||
func New(isMulti bool, Cmp ...comparator.Comparator) (t *treap) {
|
||||
//设置默认比较器
|
||||
var cmp comparator.Comparator
|
||||
if len(Cmp) > 0 {
|
||||
cmp = Cmp[0]
|
||||
}
|
||||
//创建随机数生成器
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
return &treap{
|
||||
root: nil,
|
||||
size: 0,
|
||||
cmp: cmp,
|
||||
rand: r,
|
||||
isMulti: isMulti,
|
||||
mutex: sync.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
//@title Iterator
|
||||
//@description
|
||||
// 以treap树堆做接收者
|
||||
// 将该树堆中所有保存的元素将从根节点开始以中缀序列的形式放入迭代器中
|
||||
// 若允许重复存储则对于重复元素进行多次放入
|
||||
//@receiver t *treap 接受者treap的指针
|
||||
//@param nil
|
||||
//@return i *iterator.Iterator 新建的Iterator迭代器指针
|
||||
func (t *treap) Iterator() (i *Iterator.Iterator) {
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
t.mutex.Lock()
|
||||
es := t.root.inOrder()
|
||||
i = Iterator.New(&es)
|
||||
t.mutex.Unlock()
|
||||
return i
|
||||
}
|
||||
|
||||
//@title Size
|
||||
//@description
|
||||
// 以treap树堆做接收者
|
||||
// 返回该容器当前含有元素的数量
|
||||
// 如果容器为nil返回0
|
||||
//@receiver t *treap 接受者treap的指针
|
||||
//@param nil
|
||||
//@return num int 容器中实际使用元素所占空间大小
|
||||
func (t *treap) Size() (num int) {
|
||||
if t == nil {
|
||||
return 0
|
||||
}
|
||||
return t.size
|
||||
}
|
||||
//@title Clear
|
||||
//@description
|
||||
// 以treap树堆做接收者
|
||||
// 将该容器中所承载的元素清空
|
||||
// 将该容器的size置0
|
||||
//@receiver t *treap 接受者treap的指针
|
||||
//@param nil
|
||||
//@return nil
|
||||
func (t *treap) Clear() {
|
||||
if t == nil {
|
||||
return
|
||||
}
|
||||
t.mutex.Lock()
|
||||
t.root = nil
|
||||
t.size = 0
|
||||
t.mutex.Unlock()
|
||||
}
|
||||
//@title Empty
|
||||
//@description
|
||||
// 以treap树堆做接收者
|
||||
// 判断该二叉搜索树是否含有元素
|
||||
// 如果含有元素则不为空,返回false
|
||||
// 如果不含有元素则说明为空,返回true
|
||||
// 如果容器不存在,返回true
|
||||
//@receiver t *treap 接受者treap的指针
|
||||
//@param nil
|
||||
//@return b bool 该容器是空的吗?
|
||||
func (t *treap) Empty() (b bool) {
|
||||
if t == nil {
|
||||
return true
|
||||
}
|
||||
if t.size > 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
//@title Insert
|
||||
//@description
|
||||
// 以treap树堆做接收者
|
||||
// 向二叉树插入元素e,若不允许重复则对相等元素进行覆盖
|
||||
// 如果二叉树为空则之间用根节点承载元素e,否则以根节点开始进行查找
|
||||
// 对于该树堆来说,通过赋予随机的优先级根据堆的性质来实现平衡
|
||||
//@receiver t *treap 接受者treap的指针
|
||||
//@param e interface{} 待插入元素
|
||||
//@return nil
|
||||
func (t *treap) Insert(e interface{}) {
|
||||
//判断容器是否存在
|
||||
if t == nil {
|
||||
return
|
||||
}
|
||||
t.mutex.Lock()
|
||||
if t.Empty() {
|
||||
//判断比较器是否存在
|
||||
if t.cmp == nil {
|
||||
t.cmp = comparator.GetCmp(e)
|
||||
}
|
||||
if t.cmp == nil {
|
||||
t.mutex.Unlock()
|
||||
return
|
||||
}
|
||||
//插入到根节点
|
||||
t.root = newNode(e, t.rand)
|
||||
t.size = 1
|
||||
t.mutex.Unlock()
|
||||
return
|
||||
}
|
||||
//从根节点向下插入
|
||||
if t.root.insert(newNode(e, t.rand), t.isMulti, t.cmp) {
|
||||
t.size++
|
||||
}
|
||||
t.mutex.Unlock()
|
||||
}
|
||||
|
||||
|
||||
//@title Erase
|
||||
//@description
|
||||
// 以treap树堆做接收者
|
||||
// 从树堆中删除元素e
|
||||
// 若允许重复记录则对承载元素e的节点中数量记录减一即可
|
||||
// 若不允许重复记录则删除该节点同时将前缀节点或后继节点更换过来以保证树堆的不发送断裂
|
||||
// 交换后根据优先级进行左右旋转以保证符合堆的性质
|
||||
// 如果该树堆仅持有一个元素且根节点等价于待删除元素,则将根节点置为nil
|
||||
//@receiver t *treap 接受者treap的指针
|
||||
//@param e interface{} 待删除元素
|
||||
//@return nil
|
||||
func (t *treap) Erase(e interface{}) {
|
||||
if t == nil {
|
||||
return
|
||||
}
|
||||
if t.Empty() {
|
||||
return
|
||||
}
|
||||
t.mutex.Lock()
|
||||
if t.size == 1 && t.cmp(t.root.value, e) == 0 {
|
||||
//该树堆仅持有一个元素且根节点等价于待删除元素,则将根节点置为nil
|
||||
t.root = nil
|
||||
t.size = 0
|
||||
t.mutex.Unlock()
|
||||
return
|
||||
}
|
||||
//从根节点开始删除元素
|
||||
if t.root.delete(e, t.isMulti, t.cmp) {
|
||||
//删除成功
|
||||
t.size--
|
||||
}
|
||||
t.mutex.Unlock()
|
||||
}
|
||||
|
||||
//@title Count
|
||||
//@description
|
||||
// 以treap树堆做接收者
|
||||
// 从树堆中查找元素e的个数
|
||||
// 如果找到则返回该树堆中和元素e相同元素的个数
|
||||
// 如果不允许重复则最多返回1
|
||||
// 如果未找到则返回0
|
||||
//@receiver t *treap 接受者treap的指针
|
||||
//@param e interface{} 待查找元素
|
||||
//@return num int 待查找元素在树堆中存储的个数
|
||||
func (t *treap) Count(e interface{}) (num int) {
|
||||
if t == nil {
|
||||
//树堆不存在,直接返回0
|
||||
return 0
|
||||
}
|
||||
if t.Empty() {
|
||||
return
|
||||
}
|
||||
t.mutex.Lock()
|
||||
num = t.root.search(e, t.cmp)
|
||||
t.mutex.Unlock()
|
||||
//树堆存在,从根节点开始查找该元素
|
||||
return num
|
||||
}
|
Reference in New Issue
Block a user