diff --git a/goSTL/data_structure/avlTree/avlTree.go b/goSTL/data_structure/avlTree/avlTree.go new file mode 100644 index 0000000..51d476f --- /dev/null +++ b/goSTL/data_structure/avlTree/avlTree.go @@ -0,0 +1,259 @@ +package avlTree + +//@Title avlTree +//@Description +// 平衡二叉树-Balanced Binary Tree +// 以二叉树的形式实现 +// 平衡二叉树实例保存根节点和比较器以及保存的数量 +// 可以在创建时设置节点是否可重复 +// 若节点可重复则增加节点中的数值,否则对节点存储元素进行覆盖 +// 平衡二叉树在添加和删除时都将对节点进行平衡,以保证一个节点的左右子节点高度差不超过1 +// 使用互斥锁实现并发控制 + +import ( + "github.com/hlccd/goSTL/utils/comparator" + "github.com/hlccd/goSTL/utils/iterator" + "sync" +) + +//avlTree平衡二叉树结构体 +//该实例存储平衡二叉树的根节点 +//同时保存该二叉树已经存储了多少个元素 +//二叉树中排序使用的比较器在创建时传入,若不传入则在插入首个节点时从默认比较器中寻找 +//创建时传入是否允许该二叉树出现重复值,如果不允许则进行覆盖,允许则对节点数目增加即可 +type avlTree struct { + root *node //根节点指针 + size int //存储元素数量 + cmp comparator.Comparator //比较器 + isMulti bool //是否允许重复 + mutex sync.Mutex //并发控制锁 +} + +//avlTree平衡二叉树容器接口 +//存放了avlTree平衡二叉树可使用的函数 +//对应函数介绍见下方 +type avlTreer 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 +// 新建一个avlTree平衡二叉树容器并返回 +// 初始根节点为nil +// 传入该二叉树是否为可重复属性,如果为true则保存重复值,否则对原有相等元素进行覆盖 +// 若有传入的比较器,则将传入的第一个比较器设为该二叉树的比较器 +//@receiver nil +//@param isMulti bool 该二叉树是否保存重复值? +//@param Cmp ...comparator.Comparator avlTree比较器集 +//@return avl *avlTree 新建的avlTree指针 +func New(isMulti bool, cmps ...comparator.Comparator) (avl *avlTree) { + //判断是否有传入比较器,若有则设为该二叉树默认比较器 + var cmp comparator.Comparator + if len(cmps) == 0 { + cmp = nil + } else { + cmp = cmps[0] + } + return &avlTree{ + root: nil, + size: 0, + cmp: cmp, + isMulti: isMulti, + } +} + +//@title Iterator +//@description +// 以avlTree平衡二叉树做接收者 +// 将该二叉树中所有保存的元素将从根节点开始以中缀序列的形式放入迭代器中 +// 若允许重复存储则对于重复元素进行多次放入 +//@receiver avl *avlTree 接受者avlTree的指针 +//@param nil +//@return i *iterator.Iterator 新建的Iterator迭代器指针 +func (avl *avlTree) Iterator() (i *Iterator.Iterator) { + if avl == nil { + return nil + } + avl.mutex.Lock() + es:=avl.root.inOrder() + i = Iterator.New(&es) + avl.mutex.Unlock() + return i +} + +//@title Size +//@description +// 以avlTree平衡二叉树做接收者 +// 返回该容器当前含有元素的数量 +// 如果容器为nil返回0 +//@receiver avl *avlTree 接受者avlTree的指针 +//@param nil +//@return num int 容器中实际使用元素所占空间大小 +func (avl *avlTree) Size() (num int) { + if avl == nil { + return 0 + } + return avl.size +} + +//@title Clear +//@description +// 以avlTree平衡二叉树做接收者 +// 将该容器中所承载的元素清空 +// 将该容器的size置0 +//@receiver avl *avlTree 接受者avlTree的指针 +//@param nil +//@return nil +func (avl *avlTree) Clear() { + if avl == nil { + return + } + avl.mutex.Lock() + avl.root = nil + avl.size = 0 + avl.mutex.Unlock() +} + +//@title Empty +//@description +// 以avlTree平衡二叉树做接收者 +// 判断该二叉搜索树是否含有元素 +// 如果含有元素则不为空,返回false +// 如果不含有元素则说明为空,返回true +// 如果容器不存在,返回true +//@receiver avl *avlTree 接受者avlTree的指针 +//@param nil +//@return b bool 该容器是空的吗? +func (avl *avlTree) Empty() (b bool) { + if avl == nil { + return true + } + if avl.size > 0 { + return false + } + return true +} + +//@title Insert +//@description +// 以avlTree平衡二叉树做接收者 +// 向二叉树插入元素e,若不允许重复则对相等元素进行覆盖 +// 如果二叉树为空则之间用根节点承载元素e,否则以根节点开始进行查找 +// 当节点左右子树高度差超过1时将进行旋转以保持平衡 +//@receiver avl *avlTree 接受者avlTree的指针 +//@param e interface{} 待插入元素 +//@return nil +func (avl *avlTree) Insert(e interface{}) { + if avl == nil { + return + } + avl.mutex.Lock() + if avl.Empty() { + if avl.cmp == nil { + avl.cmp = comparator.GetCmp(e) + } + if avl.cmp == nil { + return + } + //二叉树为空,用根节点承载元素e + avl.root = newNode(e) + avl.size = 1 + avl.mutex.Unlock() + return + } + //从根节点进行插入,并返回节点,同时返回是否插入成功 + var b bool + avl.root, b = avl.root.insert(e, avl.isMulti, avl.cmp) + if b { + //插入成功,数量+1 + avl.size++ + } + avl.mutex.Unlock() +} + +//@title Erase +//@description +// 以avlTree平衡二叉树做接收者 +// 从平衡二叉树中删除元素e +// 若允许重复记录则对承载元素e的节点中数量记录减一即可 +// 若不允许重复记录则删除该节点同时将前缀节点或后继节点更换过来以保证二叉树的不发送断裂 +// 如果该二叉树仅持有一个元素且根节点等价于待删除元素,则将二叉树根节点置为nil +//@receiver avl *avlTree 接受者avlTree的指针 +//@param e interface{} 待删除元素 +//@return nil +func (avl *avlTree) Erase(e interface{}) { + if avl == nil { + return + } + if avl.Empty() { + return + } + avl.mutex.Lock() + if avl.size == 1 && avl.cmp(avl.root.value, e) == 0 { + //二叉树仅持有一个元素且根节点等价于待删除元素,将二叉树根节点置为nil + avl.root = nil + avl.size = 0 + avl.mutex.Unlock() + return + } + //从根节点进行插入,并返回节点,同时返回是否删除成功 + var b bool + avl.root, b = avl.root.erase(e, avl.cmp) + if b { + avl.size-- + } + avl.mutex.Unlock() +} + +//@title Count +//@description +// 以avlTree平衡二叉树做接收者 +// 从搜素二叉树中查找元素e的个数 +// 如果找到则返回该二叉树中和元素e相同元素的个数 +// 如果不允许重复则最多返回1 +// 如果未找到则返回0 +//@receiver avl *avlTree 接受者avlTree的指针 +//@param e interface{} 待查找元素 +//@return num int 待查找元素在二叉树中存储的个数 +func (avl *avlTree) Count(e interface{}) (num int) { + if avl == nil { + //二叉树为空,返回0 + return 0 + } + if avl.Empty() { + return 0 + } + avl.mutex.Lock() + num = avl.root.count(e, avl.isMulti, avl.cmp) + avl.mutex.Unlock() + return num +} + +//@title Find +//@description +// 以avlTree平衡二叉树做接收者 +// 从搜素二叉树中查找以元素e为索引信息的全部信息 +// 如果找到则返回该二叉树中和索引元素e相同的元素的全部信息 +// 如果未找到则返回nil +//@receiver avl *avlTree 接受者avlTree的指针 +//@param e interface{} 待查找索引元素 +//@return ans interface{} 待查找索引元素所指向的元素 +func (avl *avlTree) Find(e interface{}) (ans interface{}) { + if avl == nil { + //二叉树为空,返回0 + return 0 + } + if avl.Empty() { + return 0 + } + avl.mutex.Lock() + ans = avl.root.find(e, avl.isMulti, avl.cmp) + avl.mutex.Unlock() + return ans +} diff --git a/goSTL/data_structure/avlTree/node.go b/goSTL/data_structure/avlTree/node.go new file mode 100644 index 0000000..6ee759a --- /dev/null +++ b/goSTL/data_structure/avlTree/node.go @@ -0,0 +1,372 @@ +package avlTree + +//@Title avlTree +//@Description +// 平衡二叉树的节点 +// 可通过节点实现平衡二叉树的添加删除 +// 也可通过节点返回整个平衡二叉树的所有元素 +// 增减节点后通过左右旋转的方式保持平衡二叉树的平衡 +import ( + "github.com/hlccd/goSTL/utils/comparator" +) + +//node树节点结构体 +//该节点是平衡二叉树的树节点 +//若该平衡二叉树允许重复则对节点num+1即可,否则对value进行覆盖 +//平衡二叉树节点当左右子节点深度差超过1时进行左右旋转以实现平衡 +type node struct { + value interface{} //节点中存储的元素 + num int //该元素数量 + depth int //该节点的深度 + left *node //左节点指针 + right *node //右节点指针 +} + +//@title newNode +//@description +// 新建一个平衡二叉树节点并返回 +// 将传入的元素e作为该节点的承载元素 +// 该节点的num和depth默认为1,左右子节点设为nil +//@receiver nil +//@param e interface{} 承载元素e +//@return n *node 新建的二叉搜索树节点的指针 +func newNode(e interface{}) (n *node) { + return &node{ + value: e, + num: 1, + depth: 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 getDepth +//@description +// 以node平衡二叉树节点做接收者 +// 返回该节点的深度,节点不存在返回0 +//@receiver n *node 接受者node的指针 +//@param nil +//@return depth int 该节点的深度 +func (n *node) getDepth() (depth int) { + if n == nil { + return 0 + } + return n.depth +} + +//@title max +//@description +// 返回a和b中较大的值 +//@receiver nil +//@param a int 带比较的值 +//@param b int 带比较的值 +//@return m int 两个值中较大的值 +func max(a, b int) (m int) { + if a > b { + return a + } else { + return b + } +} + +//@title leftRotate +//@description +// 以node平衡二叉树节点做接收者 +// 将该节点向左节点方向转动,使右节点作为原来节点,并返回右节点 +// 同时将右节点的左节点设为原节点的右节点 +//@receiver n *node 接受者node的指针 +//@param nil +//@return m *node 旋转后的原节点 +func (n *node) leftRotate() (m *node) { + //左旋转 + headNode := n.right + n.right = headNode.left + headNode.left = n + //更新结点高度 + n.depth = max(n.left.getDepth(), n.right.getDepth()) + 1 + headNode.depth = max(headNode.left.getDepth(), headNode.right.getDepth()) + 1 + return headNode +} + +//@title rightRotate +//@description +// 以node平衡二叉树节点做接收者 +// 将该节点向右节点方向转动,使左节点作为原来节点,并返回左节点 +// 同时将左节点的右节点设为原节点的左节点 +//@receiver n *node 接受者node的指针 +//@param nil +//@return m *node 旋转后的原节点 +func (n *node) rightRotate() (m *node) { + //右旋转 + headNode := n.left + n.left = headNode.right + headNode.right = n + //更新结点高度 + n.depth = max(n.left.getDepth(), n.right.getDepth()) + 1 + headNode.depth = max(headNode.left.getDepth(), headNode.right.getDepth()) + 1 + return headNode +} + +//@title rightLeftRotate +//@description +// 以node平衡二叉树节点做接收者 +// 将原节点的右节点先进行右旋再将原节点进行左旋 +//@receiver n *node 接受者node的指针 +//@param nil +//@return m *node 旋转后的原节点 +func (n *node) rightLeftRotate() (m *node) { + //右旋转,之后左旋转 + //以失衡点右结点先右旋转 + sonHeadNode := n.right.rightRotate() + n.right = sonHeadNode + //再以失衡点左旋转 + return n.leftRotate() +} + +//@title leftRightRotate +//@description +// 以node平衡二叉树节点做接收者 +// 将原节点的左节点先进行左旋再将原节点进行右旋 +//@receiver n *node 接受者node的指针 +//@param nil +//@return m *node 旋转后的原节点 +func (n *node) leftRightRotate() (m *node) { + //左旋转,之后右旋转 + //以失衡点左结点先左旋转 + sonHeadNode := n.left.leftRotate() + n.left = sonHeadNode + //再以失衡点左旋转 + return n.rightRotate() +} + +//@title getMin +//@description +// 以node平衡二叉树节点做接收者 +// 返回n节点的最小元素的承载的元素和数量 +// 即该节点父节点的后缀节点的元素和数量 +//@receiver n *node 接受者node的指针 +//@param nil +//@return e interface{} 前缀节点元素 +func (n *node) getMin() (e interface{}, num int) { + if n == nil { + return nil, 0 + } + if n.left == nil { + return n.value, n.num + } else { + return n.left.getMin() + } +} + +//@title adjust +//@description +// 以node平衡二叉树节点做接收者 +// 对n节点进行旋转以保持节点左右子树平衡 +//@receiver n *node 接受者node的指针 +//@param nil +//@return m *node 调整后的n节点 +func (n *node) adjust() (m *node) { + if n.right.getDepth()-n.left.getDepth() >= 2 { + //右子树高于左子树且高度差超过2,此时应当对n进行左旋 + if n.right.right.getDepth() > n.right.left.getDepth() { + //由于右右子树高度超过右左子树,故可以直接左旋 + n = n.leftRotate() + } else { + //由于右右子树不高度超过右左子树 + //所以应该先右旋右子树使得右子树高度不超过左子树 + //随后n节点左旋 + n = n.rightLeftRotate() + } + } else if n.left.getDepth()-n.right.getDepth() >= 2 { + //左子树高于右子树且高度差超过2,此时应当对n进行右旋 + if n.left.left.getDepth() > n.left.right.getDepth() { + //由于左左子树高度超过左右子树,故可以直接右旋 + n = n.rightRotate() + } else { + //由于左左子树高度不超过左右子树 + //所以应该先左旋左子树使得左子树高度不超过右子树 + //随后n节点右旋 + n = n.leftRightRotate() + } + } + return n +} + +//@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 interface{}, isMulti bool, cmp comparator.Comparator) (m *node, b bool) { + //节点不存在,应该创建并插入二叉树中 + if n == nil { + return newNode(e), true + } + if cmp(e, n.value) < 0 { + //从左子树继续插入 + n.left, b = n.left.insert(e, isMulti, cmp) + if b { + //插入成功,对该节点进行平衡 + n = n.adjust() + } + n.depth = max(n.left.getDepth(), n.right.getDepth()) + 1 + return n, b + } + if cmp(e, n.value) > 0 { + //从右子树继续插入 + n.right, b = n.right.insert(e, isMulti, cmp) + if b { + //插入成功,对该节点进行平衡 + n = n.adjust() + } + n.depth = max(n.left.getDepth(), n.right.getDepth()) + 1 + return n, b + } + //该节点元素与待插入元素相同 + if isMulti { + //允许重复,数目+1 + n.num++ + return n, true + } + //不允许重复,对值进行覆盖 + n.value = e + return n, false +} + +//@title erase +//@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) erase(e interface{}, cmp comparator.Comparator) (m *node, b bool) { + if n == nil { + //待删除值不存在,删除失败 + return n, false + } + if cmp(e, n.value) < 0 { + //从左子树继续删除 + n.left, b = n.left.erase(e, cmp) + } else if cmp(e, n.value) > 0 { + //从右子树继续删除 + n.right, b = n.right.erase(e, cmp) + } else if cmp(e, n.value) == 0 { + //存在相同值,从该节点删除 + b = true + if n.num > 1 { + //有重复值,节点无需删除,直接-1即可 + n.num-- + } else { + //该节点需要被删除 + if n.left != nil && n.right != nil { + //找到该节点后继节点进行交换删除 + n.value, n.num = n.right.getMin() + //从右节点继续删除,同时可以保证删除的节点必然无左节点 + n.right, b = n.right.erase(n.value, cmp) + } else if n.left != nil { + n = n.left + } else { + n = n.right + } + } + } + //当n节点仍然存在时,对其进行调整 + if n != nil { + n.depth = max(n.left.getDepth(), n.right.getDepth()) + 1 + n = n.adjust() + } + return n, b +} + +//@title count +//@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) count(e interface{}, isMulti bool, cmp comparator.Comparator) (num int) { + if n == nil { + return 0 + } + //n中承载元素小于e,从右子树继续查找并返回结果 + if cmp(n.value, e) < 0 { + return n.right.count(e, isMulti, cmp) + } + //n中承载元素大于e,从左子树继续查找并返回结果 + if cmp(n.value, e) > 0 { + return n.left.count(e, isMulti, cmp) + } + //n中承载元素等于e,直接返回结果 + return n.num +} + +//@title find +//@description +// 以node二叉搜索树节点做接收者 +// 从n节点中查找元素e并返回其存储的全部信息 +// 如果n节点中承载元素与e不同则根据大小从左右子树查找该元素 +// 如果n节点与该元素相等,则直接返回其信息即可 +// 若未找到该索引信息则返回nil +//@receiver n *node 接受者node的指针 +//@param e interface{} 待查找元素 +//@param isMulti bool 是否允许重复? +//@param cmp comparator.Comparator 判断大小的比较器 +//@return ans interface{} 待查找索引元素所指向的元素 +func (n *node) find(e interface{}, isMulti bool, cmp comparator.Comparator) (ans interface{}) { + if n == nil { + return nil + } + //n中承载元素小于e,从右子树继续查找并返回结果 + if cmp(n.value, e) < 0 { + return n.right.count(e, isMulti, cmp) + } + //n中承载元素大于e,从左子树继续查找并返回结果 + if cmp(n.value, e) > 0 { + return n.left.count(e, isMulti, cmp) + } + //n中承载元素等于e,直接返回结果 + return n.value +} diff --git a/goSTL/data_structure/treap/node.go b/goSTL/data_structure/treap/node.go index d1ad26d..1b24baa 100644 --- a/goSTL/data_structure/treap/node.go +++ b/goSTL/data_structure/treap/node.go @@ -16,7 +16,7 @@ import ( //树堆节点将针对堆的性质通过左右旋转的方式做平衡 type node struct { value interface{} //节点中存储的元素 - priority uint16 //该节点的优先级,随机生成 + priority uint32 //该节点的优先级,随机生成 num int //该节点中存储的数量 left *node //左节点指针 right *node //右节点指针 @@ -35,7 +35,7 @@ type node struct { func newNode(e interface{}, rand *rand.Rand) (n *node) { return &node{ value: e, - priority: uint16(rand.Intn(65535)), + priority: uint32(rand.Intn(4294967295)), num: 1, left: nil, right: nil,