新增堆的完全二叉树实现,线程安全

This commit is contained in:
hlccd 2021-10-26 17:17:18 +08:00 committed by GitHub
parent 9c7d289c16
commit f20baf0898
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 816 additions and 0 deletions

View File

@ -0,0 +1,217 @@
package cbTree
//@Title cbTree
//@Description
// 完全二叉树-Complete Binary Tree
// 以完全二叉树的形式实现的堆
// 通过比较器判断传入元素的大小
// 将最小的元素放在堆顶
// 该结构只保留整个树的根节点,其他节点通过根节点进行查找获得
//@author hlccd 2021-07-14
//@update hlccd 2021-08-01 增加互斥锁实现并发控制
import (
"github.com/hlccd/goSTL/utils/comparator"
"github.com/hlccd/goSTL/utils/iterator"
"sync"
)
//cbTree完全二叉树树结构体
//该实例存储二叉树的根节点
//同时保存该二叉树已经存储了多少个元素
//二叉树中排序使用的比较器在创建时传入,若不传入则在插入首个节点时从默认比较器中寻找
type cbTree struct {
root *node //根节点指针
size int //存储元素数量
cmp comparator.Comparator //比较器
mutex sync.Mutex //并发控制锁
}
//cbTree二叉搜索树容器接口
//存放了cbTree二叉搜索树可使用的函数
//对应函数介绍见下方
type cbTreer interface {
Iterator() (i *iterator.Iterator) //返回包含该二叉树的所有元素
Size() (num int) //返回该二叉树中保存的元素个数
Clear() //清空该二叉树
Empty() (b bool) //判断该二叉树是否为空
Push(e interface{}) //向二叉树中插入元素e
Pop() //从二叉树中弹出顶部元素
Top() (e interface{}) //返回该二叉树的顶部元素
}
//@title New
//@description
// 新建一个cbTree完全二叉树容器并返回
// 初始根节点为nil
// 若有传入的比较器,则将传入的第一个比较器设为该二叉树的比较器
//@author hlccd 2021-07-14
//@receiver nil
//@param Cmp ...comparator.Comparator cbTree比较器集
//@return cb *cbTree 新建的cbTree指针
func New(Cmp ...comparator.Comparator) (cb *cbTree) {
//判断是否有传入比较器,若有则设为该二叉树默认比较器
var cmp comparator.Comparator
if len(Cmp) > 0 {
cmp = Cmp[0]
}
return &cbTree{
root: nil,
size: 0,
cmp: cmp,
mutex: sync.Mutex{},
}
}
//@title Iterator
//@description
// 以cbTree完全二叉树做接收者
// 将该二叉树中所有保存的元素将从根节点开始以前缀序列的形式放入迭代器中
//@auth hlccd 2021-07-14
//@receiver cb *cbTree 接受者cbTree的指针
//@param nil
//@return i *iterator.Iterator 新建的Iterator迭代器指针
func (cb *cbTree) Iterator() (i *iterator.Iterator) {
if cb == nil {
return iterator.New(make([]interface{}, 0, 0))
}
cb.mutex.Lock()
i = iterator.New(cb.root.frontOrder())
cb.mutex.Unlock()
return i
}
//@title Size
//@description
// 以cbTree完全二叉树做接收者
// 返回该容器当前含有元素的数量
// 如果容器为nil返回-1
//@auth hlccd 2021-07-14
//@receiver cb *cbTree 接受者cbTree的指针
//@param nil
//@return num int 容器中实际使用元素所占空间大小
func (cb *cbTree) Size() (num int) {
if cb == nil {
return -1
}
return cb.size
}
//@title Clear
//@description
// 以cbTree完全二叉树做接收者
// 将该容器中所承载的元素清空
// 将该容器的size置0
//@auth hlccd 2021-07-14
//@receiver cb *cbTree 接受者cbTree的指针
//@param nil
//@return nil
func (cb *cbTree) Clear() {
if cb == nil {
return
}
cb.mutex.Lock()
cb.root = nil
cb.size = 0
cb.mutex.Unlock()
}
//@title Empty
//@description
// 以cbTree完全二叉树做接收者
// 判断该完全二叉树树是否含有元素
// 如果含有元素则不为空,返回false
// 如果不含有元素则说明为空,返回true
// 如果容器不存在,返回true
//@auth hlccd 2021-07-14
//@receiver cb *cbTree 接受者cbTree的指针
//@param nil
//@return b bool 该容器是空的吗?
func (cb *cbTree) Empty() (b bool) {
if cb == nil {
return true
}
if cb.size > 0 {
return false
}
return true
}
//@title Push
//@description
// 以cbTree完全二叉树做接收者
// 向二叉树插入元素e,将其放入完全二叉树的最后一个位置,随后进行元素上升
// 如果二叉树本身为空,则直接将根节点设为插入节点元素即可
//@auth hlccd 2021-07-14
//@receiver cb *cbTree 接受者cbTree的指针
//@param e interface{} 待插入元素
//@return nil
func (cb *cbTree) Push(e interface{}) {
if cb == nil {
return
}
cb.mutex.Lock()
if cb.Empty() {
if cb.cmp == nil {
cb.cmp = comparator.GetCmp(e)
}
if cb.cmp == nil {
cb.mutex.Unlock()
return
}
cb.root = newNode(nil, e)
cb.size++
} else {
cb.size++
cb.root.insert(cb.size, e, cb.cmp)
}
cb.mutex.Unlock()
}
//@title Pop
//@description
// 以cbTree完全二叉树做接收者
// 从完全二叉树中删除顶部元素e
// 将该顶部元素于最后一个元素进行交换
// 随后删除最后一个元素
// 再将顶部元素进行下沉处理即可
//@auth hlccd 2021-07-14
//@receiver cb *cbTree 接受者cbTree的指针
//@param nil
//@return nil
func (cb *cbTree) Pop() {
if cb == nil {
return
}
if cb.Empty() {
return
}
cb.mutex.Lock()
if cb.size == 1 {
//该二叉树仅剩根节点,直接删除即可
cb.root = nil
} else {
//该二叉树删除根节点后还有其他节点可生为跟节点
cb.root.delete(cb.size, cb.cmp)
}
cb.size--
cb.mutex.Unlock()
}
//@title Top
//@description
// 以cbTree完全二叉树做接收者
// 返回该完全二叉树的顶部元素
// 当该完全二叉树不存在或根节点不存在时返回nil
//@auth hlccd 2021-07-14
//@receiver cb *cbTree 接受者cbTree的指针
//@param nil
//@return e interface{} 该完全二叉树的顶部元素
func (cb *cbTree) Top() (e interface{}) {
if cb == nil {
return nil
}
cb.mutex.Lock()
e = cb.root.value
cb.mutex.Unlock()
return e
}

View File

@ -0,0 +1,200 @@
package cbTree
//@Title cbTree
//@Description
// 完全二叉树的节点
// 可通过节点实现完全二叉树的节点上升与下沉
// 也可查找待插入的最后一个节点的父节点,即该待插入节点将放入该父节点的左右子节点中
//@author hlccd 2021-07-14
import "github.com/hlccd/goSTL/utils/comparator"
//node树节点结构体
//该节点是完全二叉树的树节点
//该节点除了保存承载元素外,还将保存父节点、左右子节点的指针
type node struct {
value interface{} //节点中存储的元素
parent *node //父节点指针
left *node //左节点指针
right *node //右节点指针
}
//@title newNode
//@description
// 新建一个完全二叉树节点并返回
// 将传入的元素e作为该节点的承载元素
// 将传入的parent节点作为其父节点,左右节点设为nil
//@auth hlccd 2021-07-14
//@receiver nil
//@param parent *node 新建节点的父节点指针
//@param e interface{} 承载元素e
//@return n *node 新建的完全二叉树节点的指针
func newNode(parent *node, e interface{}) (n *node) {
return &node{
value: e,
parent: parent,
left: nil,
right: nil,
}
}
//@title frontOrder
//@description
// 以node节点做接收者
// 以前缀序列返回节点集合
//@auth hlccd 2021-07-14
//@receiver n *node 接受者node的指针
//@param nil
//@return es []interface{} 以该节点为起点的前缀序列
func (n *node) frontOrder() (es []interface{}) {
if n == nil {
return es
}
es = append(es, n.value)
if n.left != nil {
es = append(es, n.left.frontOrder()...)
}
if n.right != nil {
es = append(es, n.right.frontOrder()...)
}
return es
}
//@title lastParent
//@description
// 以node节点做接收者
// 根据传入数值通过转化为二进制的方式模拟查找最后一个父节点
// 由于查找父节点的路径等同于转化为二进制后除开首位的中间值,故该方案是可行的
//@auth hlccd 2021-07-14
//@receiver n *node 接受者node的指针
//@param nil
//@return ans *node 查找到的最后一个父节点
func (n *node) lastParent(num int) (ans *node) {
if num > 3 {
//去掉末尾的二进制值
arr := make([]int, 0, 32)
ans = n
for num > 0 {
//转化为二进制
arr = append(arr, num%2)
num /= 2
}
//去掉首位的二进制值
for i := len(arr) - 2; i >= 1; i-- {
if arr[i] == 1 {
ans = ans.right
} else {
ans = ans.left
}
}
return ans
}
return n
}
//@title insert
//@description
// 以node节点做接收者
// 从该节点插入元素e,并根据传入的num寻找最后一个父节点用于插入最后一位值
// 随后对插入值进行上升处理
//@auth hlccd 2021-07-14
//@receiver n *node 接受者node的指针
//@param num int 插入后的元素数量,用于寻找最后一个父节点
//@param e interface{} 待插入元素
//@param cmp comparator.Comparator 比较器,在节点上升时使用
//@return nil
func (n *node) insert(num int, e interface{}, cmp comparator.Comparator) {
if n == nil {
return
}
//寻找最后一个父节点
n = n.lastParent(num)
//将元素插入最后一个节点
if num%2 == 0 {
n.left = newNode(n, e)
n = n.left
} else {
n.right = newNode(n, e)
n = n.right
}
//对插入的节点进行上升
n.up(cmp)
}
//@title up
//@description
// 以node节点做接收者
// 对该节点进行上升
// 当该节点存在且父节点存在时,若该节点小于夫节点
// 则在交换两个节点值后继续上升即可
//@auth hlccd 2021-07-14
//@receiver n *node 接受者node的指针
//@param cmp comparator.Comparator 比较器,在节点上升时使用
//@return nil
func (n *node) up(cmp comparator.Comparator) {
if n == nil {
return
}
if n.parent == nil {
return
}
//该节点和父节点都存在
if cmp(n.parent.value, n.value) > 0 {
//该节点值小于父节点值,交换两节点值,继续上升
n.parent.value, n.value = n.value, n.parent.value
n.parent.up(cmp)
}
}
//@title delete
//@description
// 以node节点做接收者
// 从删除该,并根据传入的num寻找最后一个父节点用于替换删除
// 随后对替换后的值进行下沉处理即可
//@auth hlccd 2021-07-14
//@receiver n *node 接受者node的指针
//@param num int 删除前的元素数量,用于寻找最后一个父节点
//@param cmp comparator.Comparator 比较器,在节点下沉时使用
//@return nil
func (n *node) delete(num int, cmp comparator.Comparator) {
if n == nil {
return
}
//寻找最后一个父节点
ln := n.lastParent(num)
if num%2 == 0 {
n.value = ln.left.value
ln.left = nil
} else {
n.value = ln.right.value
ln.right = nil
}
//对交换后的节点进行下沉
n.down(cmp)
}
//@title down
//@description
// 以node节点做接收者
// 对该节点进行下沉
// 当该存在右节点且小于自身元素时,与右节点进行交换并继续下沉
// 否则当该存在左节点且小于自身元素时,与左节点进行交换并继续下沉
// 当左右节点都不存在或都大于自身时下沉停止
//@auth hlccd 2021-07-14
//@receiver n *node 接受者node的指针
//@param cmp comparator.Comparator 比较器,在节点下沉时使用
//@return nil
func (n *node) down(cmp comparator.Comparator) {
if n == nil {
return
}
if n.right != nil && cmp(n.left.value, n.right.value) >= 0 {
n.right.value, n.value = n.value, n.right.value
n.right.down(cmp)
return
}
if n.left != nil && cmp(n.value, n.left.value) >= 0 {
n.left.value, n.value = n.value, n.left.value
n.left.down(cmp)
return
}
}

View File

@ -0,0 +1,206 @@
package heap
//@Title heap
//@Description
// 采用完全二叉树-Complete Binary Tree实现堆
// 通过比较器判断传入元素的大小
// 将最小的元素放在堆顶
// 该结构只保留整个树的根节点,其他节点通过根节点进行查找获得
// 增加互斥锁实现并发控制
import (
"github.com/hlccd/goSTL/utils/comparator"
"github.com/hlccd/goSTL/utils/iterator"
"sync"
)
//cbTree完全二叉树树结构体
//该实例存储二叉树的根节点
//同时保存该二叉树已经存储了多少个元素
//二叉树中排序使用的比较器在创建时传入,若不传入则在插入首个节点时从默认比较器中寻找
type cbTree struct {
root *node //根节点指针
size uint64 //存储元素数量
cmp comparator.Comparator //比较器
mutex sync.Mutex //并发控制锁
}
//cbTree二叉搜索树容器接口
//存放了cbTree二叉搜索树可使用的函数
//对应函数介绍见下方
type cbTreer interface {
Iterator() (i *Iterator.Iterator) //返回包含该二叉树的所有元素
Size() (num uint64) //返回该二叉树中保存的元素个数
Clear() //清空该二叉树
Empty() (b bool) //判断该二叉树是否为空
Push(e interface{}) //向二叉树中插入元素e
Pop() //从二叉树中弹出顶部元素
Top() (e interface{}) //返回该二叉树的顶部元素
}
//@title New
//@description
// 新建一个cbTree完全二叉树容器并返回
// 初始根节点为nil
// 若有传入的比较器,则将传入的第一个比较器设为该二叉树的比较器
//@author hlccd 2021-07-14
//@receiver nil
//@param Cmp ...comparator.Comparator cbTree比较器集
//@return cb *cbTree 新建的cbTree指针
func New(Cmp ...comparator.Comparator) (cb *cbTree) {
//判断是否有传入比较器,若有则设为该二叉树默认比较器
var cmp comparator.Comparator
if len(Cmp) > 0 {
cmp = Cmp[0]
}
return &cbTree{
root: nil,
size: 0,
cmp: cmp,
mutex: sync.Mutex{},
}
}
//@title Iterator
//@description
// 以cbTree完全二叉树做接收者
// 将该二叉树中所有保存的元素将从根节点开始以前缀序列的形式放入迭代器中
//@receiver cb *cbTree 接受者cbTree的指针
//@param nil
//@return i *Iterator.Iterator 新建的Iterator迭代器指针
func (cb *cbTree) Iterator() (i *Iterator.Iterator) {
if cb == nil {
cb = New()
}
cb.mutex.Lock()
es := cb.root.frontOrder()
i = Iterator.New(&es)
cb.mutex.Unlock()
return i
}
//@title Size
//@description
// 以cbTree完全二叉树做接收者
// 返回该容器当前含有元素的数量
// 如果容器为nil返回0
//@receiver cb *cbTree 接受者cbTree的指针
//@param nil
//@return num uint64 容器中实际使用元素所占空间大小
func (cb *cbTree) Size() (num uint64) {
if cb == nil {
cb = New()
}
return cb.size
}
//@title Clear
//@description
// 以cbTree完全二叉树做接收者
// 将该容器中所承载的元素清空
// 将该容器的size置0
//@receiver cb *cbTree 接受者cbTree的指针
//@param nil
//@return nil
func (cb *cbTree) Clear() {
if cb == nil {
cb = New()
}
cb.mutex.Lock()
cb.root = nil
cb.size = 0
cb.mutex.Unlock()
}
//@title Empty
//@description
// 以cbTree完全二叉树做接收者
// 判断该完全二叉树树是否含有元素
// 如果含有元素则不为空,返回false
// 如果不含有元素则说明为空,返回true
// 如果容器不存在,返回true
//@receiver cb *cbTree 接受者cbTree的指针
//@param nil
//@return b bool 该容器是空的吗?
func (cb *cbTree) Empty() (b bool) {
if cb == nil {
cb = New()
}
return cb.size == 0
}
//@title Push
//@description
// 以cbTree完全二叉树做接收者
// 向二叉树插入元素e,将其放入完全二叉树的最后一个位置,随后进行元素上升
// 如果二叉树本身为空,则直接将根节点设为插入节点元素即可
//@receiver cb *cbTree 接受者cbTree的指针
//@param e interface{} 待插入元素
//@return nil
func (cb *cbTree) Push(e interface{}) {
if cb == nil {
cb=New()
}
cb.mutex.Lock()
if cb.Empty() {
if cb.cmp == nil {
cb.cmp = comparator.GetCmp(e)
}
if cb.cmp == nil {
cb.mutex.Unlock()
return
}
cb.root = newNode(nil, e)
cb.size++
} else {
cb.size++
cb.root.insert(cb.size, e, cb.cmp)
}
cb.mutex.Unlock()
}
//@title Pop
//@description
// 以cbTree完全二叉树做接收者
// 从完全二叉树中删除顶部元素e
// 将该顶部元素于最后一个元素进行交换
// 随后删除最后一个元素
// 再将顶部元素进行下沉处理即可
//@receiver cb *cbTree 接受者cbTree的指针
//@param nil
//@return nil
func (cb *cbTree) Pop() {
if cb == nil {
cb=New()
}
if cb.Empty() {
return
}
cb.mutex.Lock()
if cb.size == 1 {
//该二叉树仅剩根节点,直接删除即可
cb.root = nil
} else {
//该二叉树删除根节点后还有其他节点可生为跟节点
cb.root.delete(cb.size, cb.cmp)
}
cb.size--
cb.mutex.Unlock()
}
//@title Top
//@description
// 以cbTree完全二叉树做接收者
// 返回该完全二叉树的顶部元素
// 当该完全二叉树不存在或根节点不存在时返回nil
//@receiver cb *cbTree 接受者cbTree的指针
//@param nil
//@return e interface{} 该完全二叉树的顶部元素
func (cb *cbTree) Top() (e interface{}) {
if cb == nil {
cb=New()
}
cb.mutex.Lock()
e = cb.root.value
cb.mutex.Unlock()
return e
}

View File

@ -0,0 +1,193 @@
package heap
//@Title cbTree
//@Description
// 完全二叉树的节点
// 可通过节点实现完全二叉树的节点上升与下沉
// 也可查找待插入的最后一个节点的父节点,即该待插入节点将放入该父节点的左右子节点中
import "github.com/hlccd/goSTL/utils/comparator"
//node树节点结构体
//该节点是完全二叉树的树节点
//该节点除了保存承载元素外,还将保存父节点、左右子节点的指针
type node struct {
value interface{} //节点中存储的元素
parent *node //父节点指针
left *node //左节点指针
right *node //右节点指针
}
//@title newNode
//@description
// 新建一个完全二叉树节点并返回
// 将传入的元素e作为该节点的承载元素
// 将传入的parent节点作为其父节点,左右节点设为nil
//@receiver nil
//@param parent *node 新建节点的父节点指针
//@param e interface{} 承载元素e
//@return n *node 新建的完全二叉树节点的指针
func newNode(parent *node, e interface{}) (n *node) {
return &node{
value: e,
parent: parent,
left: nil,
right: nil,
}
}
//@title frontOrder
//@description
// 以node节点做接收者
// 以前缀序列返回节点集合
//@receiver n *node 接受者node的指针
//@param nil
//@return es []interface{} 以该节点为起点的前缀序列
func (n *node) frontOrder() (es []interface{}) {
if n == nil {
return es
}
es = append(es, n.value)
if n.left != nil {
es = append(es, n.left.frontOrder()...)
}
if n.right != nil {
es = append(es, n.right.frontOrder()...)
}
return es
}
//@title lastParent
//@description
// 以node节点做接收者
// 根据传入数值通过转化为二进制的方式模拟查找最后一个父节点
// 由于查找父节点的路径等同于转化为二进制后除开首位的中间值,故该方案是可行的
//@receiver n *node 接受者node的指针
//@param num uint64 对应位置转化为二进制的值,用于查找
//@return ans *node 查找到的最后一个父节点
func (n *node) lastParent(num uint64) (ans *node) {
if num > 3 {
//去掉末尾的二进制值
arr := make([]byte, 0, 64)
ans = n
for num > 0 {
//转化为二进制
arr = append(arr, byte(num%2))
num /= 2
}
//去掉首位的二进制值
for i := len(arr) - 2; i >= 1; i-- {
if arr[i] == 1 {
ans = ans.right
} else {
ans = ans.left
}
}
return ans
}
return n
}
//@title insert
//@description
// 以node节点做接收者
// 从该节点插入元素e,并根据传入的num寻找最后一个父节点用于插入最后一位值
// 随后对插入值进行上升处理
//@receiver n *node 接受者node的指针
//@param num uint64 插入后的元素数量,用于寻找最后一个父节点
//@param e interface{} 待插入元素
//@param cmp comparator.Comparator 比较器,在节点上升时使用
//@return nil
func (n *node) insert(num uint64, e interface{}, cmp comparator.Comparator) {
if n == nil {
return
}
//寻找最后一个父节点
n = n.lastParent(num)
//将元素插入最后一个节点
if num%2 == 0 {
n.left = newNode(n, e)
n = n.left
} else {
n.right = newNode(n, e)
n = n.right
}
//对插入的节点进行上升
n.up(cmp)
}
//@title up
//@description
// 以node节点做接收者
// 对该节点进行上升
// 当该节点存在且父节点存在时,若该节点小于夫节点
// 则在交换两个节点值后继续上升即可
//@receiver n *node 接受者node的指针
//@param cmp comparator.Comparator 比较器,在节点上升时使用
//@return nil
func (n *node) up(cmp comparator.Comparator) {
if n == nil {
return
}
if n.parent == nil {
return
}
//该节点和父节点都存在
if cmp(n.parent.value, n.value) > 0 {
//该节点值小于父节点值,交换两节点值,继续上升
n.parent.value, n.value = n.value, n.parent.value
n.parent.up(cmp)
}
}
//@title delete
//@description
// 以node节点做接收者
// 从删除该,并根据传入的num寻找最后一个父节点用于替换删除
// 随后对替换后的值进行下沉处理即可
//@receiver n *node 接受者node的指针
//@param num uint64 删除前的元素数量,用于寻找最后一个父节点
//@param cmp comparator.Comparator 比较器,在节点下沉时使用
//@return nil
func (n *node) delete(num uint64, cmp comparator.Comparator) {
if n == nil {
return
}
//寻找最后一个父节点
ln := n.lastParent(num)
if num%2 == 0 {
n.value = ln.left.value
ln.left = nil
} else {
n.value = ln.right.value
ln.right = nil
}
//对交换后的节点进行下沉
n.down(cmp)
}
//@title down
//@description
// 以node节点做接收者
// 对该节点进行下沉
// 当该存在右节点且小于自身元素时,与右节点进行交换并继续下沉
// 否则当该存在左节点且小于自身元素时,与左节点进行交换并继续下沉
// 当左右节点都不存在或都大于自身时下沉停止
//@receiver n *node 接受者node的指针
//@param cmp comparator.Comparator 比较器,在节点下沉时使用
//@return nil
func (n *node) down(cmp comparator.Comparator) {
if n == nil {
return
}
if n.right != nil && cmp(n.left.value, n.right.value) >= 0 {
n.right.value, n.value = n.value, n.right.value
n.right.down(cmp)
return
}
if n.left != nil && cmp(n.value, n.left.value) >= 0 {
n.left.value, n.value = n.value, n.left.value
n.left.down(cmp)
return
}
}