diff --git a/algorithm/hash.go b/algorithm/hash.go new file mode 100644 index 0000000..87a7742 --- /dev/null +++ b/algorithm/hash.go @@ -0,0 +1,107 @@ +package algorithm + +//@Title algorithm +//@Description +// hash函数 +// 定义了一个hash函数类型,该类型可传入一个key并返回其hash值 +// 该包内定义了一些自带类型的hash函数 +// 当使用自定义的数据结构时若不传入hash函数则使用默认的hash函数 +// 若传入类型非系统自带类型,则返回nil同时对数据的插入失败 + +type Hasher func(key interface{}) uint64 + +func GetHash(e interface{}) (hash Hasher) { + if e == nil { + return nil + } + switch e.(type) { + case bool: + return boolHash + case int: + return intHash + case int8: + return int8Hash + case uint8: + return uint8Hash + case int16: + return int16Hash + case uint16: + return uint16Hash + case int32: + return int32Hash + case uint32: + return uint32Hash + case int64: + return int64Hash + case uint64: + return uint64Hash + case float32: + return float32Hash + case float64: + return float64Hash + case complex64: + return complex64Hash + case complex128: + return complex128Hash + case string: + return stringHash + } + return nil +} +func boolHash(key interface{}) uint64 { + if key.(bool) { + return 1 + } + return 0 +} +func intHash(key interface{}) uint64 { + return uint64(key.(int) * key.(int) / 2) +} +func int8Hash(key interface{}) uint64 { + return uint64(key.(int8) * key.(int8) / 2) +} +func uint8Hash(key interface{}) uint64 { + return uint64(key.(uint8) * key.(uint8) / 2) +} +func int16Hash(key interface{}) uint64 { + return uint64(key.(int16) * key.(int16) / 2) +} +func uint16Hash(key interface{}) uint64 { + return uint64(key.(uint16) * key.(uint16) / 2) +} +func int32Hash(key interface{}) uint64 { + return uint64(key.(int32) * key.(int32) / 2) +} +func uint32Hash(key interface{}) uint64 { + return uint64(key.(uint32) * key.(uint32) / 2) +} +func int64Hash(key interface{}) uint64 { + return uint64(key.(int64) * key.(int64) / 2) +} +func uint64Hash(key interface{}) uint64 { + return uint64(key.(uint64) * key.(uint64) / 2) +} +func float32Hash(key interface{}) uint64 { + return uint64(key.(float32) * key.(float32) / 2) +} +func float64Hash(key interface{}) uint64 { + return uint64(key.(float64) * key.(float64) / 2) +} +func complex64Hash(key interface{}) uint64 { + r := uint64(real(key.(complex64))) + i := uint64(imag(key.(complex64))) + return uint64Hash(r) + uint64Hash(i) +} +func complex128Hash(key interface{}) uint64 { + r := uint64(real(key.(complex64))) + i := uint64(imag(key.(complex64))) + return uint64Hash(r) + uint64Hash(i) +} +func stringHash(key interface{}) uint64 { + bs := []byte(key.(string)) + ans := uint64(0) + for i := range bs { + ans += uint64(bs[i] * 251) + } + return ans +} diff --git a/algorithm/singleFlight/singleFlight.go b/algorithm/singleFlight/singleFlight.go new file mode 100644 index 0000000..a125d2e --- /dev/null +++ b/algorithm/singleFlight/singleFlight.go @@ -0,0 +1,124 @@ +package singleFlight + +//@Title singleFlight +//@Description +// 单次请求-single flight +// 利用可重入锁避免对于一个同类的请求进行多次从而导致的缓存击穿的问题 +// 缓存击穿: +// 缓存在某个时间点过期的时候 +// 恰好在这个时间点对这个Key有大量的并发请求过来 +// 这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存 +// 这个时候大并发的请求可能会瞬间把后端DB压垮。 + +import "sync" + +//呼叫请求结构体 +type call struct { + wg sync.WaitGroup //可重入锁 + val interface{} //请求结果 + err error //错误反馈 +} + +//一组请求工作 +//每一类请求对应一个call,利用其内部的可重入锁避免一类请求在短时间内频繁执行 +//请求组工作由使用者自行分配空间来实现 +type Group struct { + m map[string]*call //一类请求与同一类呼叫的映射表 + mu sync.Mutex //并发控制锁,保证线程安全 +} + +//@title Do +//@description +// 以请求组做接收者 +// 传入一个请求类的key和请求调用函数fn +// 请求时候需要等待之前有的同类请求先完成在进行 +// 防止击穿缓存,对同一个key进行请求时需要分别进行,利用可重入锁实现 +// 请求完成后返回结果和错误信息即可 +//@receiver g *Group 接受者请求组的指针 +//@param key string 请求的关键词key +//@param fn func() (interface{}, error) 请求执行函数 +//@return v interface{} 请求执行得到的结果 +//@return err error 执行请求后的错误信息 +func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error) { + g.mu.Lock() + if g.m == nil { + g.m = make(map[string]*call) + } + //判断以key为关键词的该类请求是否存在 + if c, ok := g.m[key]; ok { + g.mu.Unlock() + // 如果请求正在进行中,则等待 + c.wg.Wait() + return c.val, c.err + } + //该类请求不存在,创建个请求 + c := new(call) + // 发起请求前加锁,并将请求添加到请求组内以表示该类请求正在处理 + c.wg.Add(1) + g.m[key] = c + g.mu.Unlock() + //调用请求函数获取内容 + c.val, c.err = fn() + //请求结束 + c.wg.Done() + g.mu.Lock() + //从请求组中删除该呼叫请求 + delete(g.m, key) + g.mu.Unlock() + return c.val, c.err +} + +//@title DoChan +//@description +// 以请求组做接收者 +// 传入一个请求类的key和请求调用函数fn +// 请求时候需要等待之前有的同类请求先完成在进行 +// 防止击穿缓存,对同一个key进行请求时需要分别进行,利用可重入锁实现 +// 返回一个channel,利用fn函数获取到的数据将会传入其中 +// 可利用channel做超时控制 +//@receiver g *Group 接受者请求组的指针 +//@param key string 请求的关键词key +//@param fn func() (interface{}, error) 请求执行函数 +//@return ch chan interface{} 执行结果将会传入其中,可做超时控制 +func (g *Group) DoChan(key string, fn func() (interface{}, error)) (ch chan interface{}) { + ch = make(chan interface{}, 1) + g.mu.Lock() + if g.m == nil { + g.m = make(map[string]*call) + } + if _, ok := g.m[key]; ok { + g.mu.Unlock() + return ch + } + c := new(call) + c.wg.Add(1) // 发起请求前加锁 + g.m[key] = c // 添加到 g.m,表明 key 已经有对应的请求在处理 + g.mu.Unlock() + go func() { + c.val, c.err = fn() // 调用 fn,发起请求 + c.wg.Done() // 请求结束 + g.mu.Lock() + delete(g.m, key) // 更新 g.m + ch <- c.val + g.mu.Unlock() + }() + return ch +} + +//@title ForgetUnshared +//@description +// 以请求组做接收者 +// 传入一个请求类的key +// 如果该key存在于请求组内,则将其删除即可 +// 从而实现遗忘该类请求的目的 +//@receiver g *Group 接受者请求组的指针 +//@param key string 请求的关键词key +//@return nil +func (g *Group) ForgetUnshared(key string) { + g.mu.Lock() + _, ok := g.m[key] + if ok { + delete(g.m, key) + } + g.mu.Unlock() +} diff --git a/data_structure/avlTree/avlTree.go b/data_structure/avlTree/avlTree.go new file mode 100644 index 0000000..7c43cf5 --- /dev/null +++ b/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{}) (b bool) //向二叉树中插入元素e + Erase(e interface{}) (b bool) //从二叉树中删除元素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 b bool 添加成功? +func (avl *AvlTree) Insert(e interface{}) (b bool) { + if avl == nil { + return false + } + 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 true + } + //从根节点进行插入,并返回节点,同时返回是否插入成功 + avl.root, b = avl.root.insert(e, avl.isMulti, avl.cmp) + if b { + //插入成功,数量+1 + avl.size++ + } + avl.mutex.Unlock() + return b +} + +//@title Erase +//@description +// 以avlTree平衡二叉树做接收者 +// 从平衡二叉树中删除元素e +// 若允许重复记录则对承载元素e的节点中数量记录减一即可 +// 若不允许重复记录则删除该节点同时将前缀节点或后继节点更换过来以保证二叉树的不发送断裂 +// 如果该二叉树仅持有一个元素且根节点等价于待删除元素,则将二叉树根节点置为nil +//@receiver avl *avlTree 接受者avlTree的指针 +//@param e interface{} 待删除元素 +//@return b bool 删除成功? +func (avl *AvlTree) Erase(e interface{}) (b bool) { + if avl == nil { + return false + } + if avl.Empty() { + return false + } + 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 true + } + //从根节点进行插入,并返回节点,同时返回是否删除成功 + avl.root, b = avl.root.erase(e, avl.cmp) + if b { + avl.size-- + } + avl.mutex.Unlock() + return b +} + +//@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/data_structure/avlTree/node.go b/data_structure/avlTree/node.go new file mode 100644 index 0000000..663dd89 --- /dev/null +++ b/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.find(e, isMulti, cmp) + } + //n中承载元素大于e,从左子树继续查找并返回结果 + if cmp(n.value, e) > 0 { + return n.left.find(e, isMulti, cmp) + } + //n中承载元素等于e,直接返回结果 + return n.value +} diff --git a/data_structure/bitmap/bitmap.go b/data_structure/bitmap/bitmap.go new file mode 100644 index 0000000..38d9e79 --- /dev/null +++ b/data_structure/bitmap/bitmap.go @@ -0,0 +1,186 @@ +package bitmap + +//@Title bitmap +//@Description +// bitmap位图容器包 +// 内部使用uint64切片进行存储 +// 由于数字在计算机内部存储时采用多个bit组成一个字符 +// 而一bit只有1和0两个情况,所以也可以使用一个bit表示任意一位存在 +// 该数据结构主要可以进行过滤去重、标注是否存在、快速排序的功能 + +//bitmap位图结构体 +//包含其用于存储的uint64元素切片 +//选用uint64是为了更多的利用bit位 +type Bitmap struct { + bits []uint64 +} + +//bitmap位图容器接口 +//存放了bitmap容器可使用的函数 +//对应函数介绍见下方 +type bitmaper interface { + Insert(num uint) //在num位插入元素 + Delete(num uint) //删除第num位 + Check(num uint) (b bool) //检查第num位是否有元素 + All() (nums []uint) //返回所有存储的元素的下标 + Clear() //清空 +} + +//@title New +//@description +// 新建一个bitmap位图容器并返回 +// 初始bitmap的切片数组为空 +//@receiver nil +//@param nil +//@return bm *Bitmap 新建的bitmap指针 +func New() (bm *Bitmap) { + return &Bitmap{ + bits: make([]uint64, 0, 0), + } +} + +//@title Insert +//@description +// 以bitmap位图容器做接收者 +// 向位图中第num位插入一个元素(下标从0开始) +// 当num大于当前所能存储的位范围时,需要进行扩增 +// 若要插入的位比冗余的多不足2^16即1024*64时,则新增1024个uint64 +// 否则则直接增加到可以容纳第num位的位置,以此可以提高冗余量,避免多次增加 +//@receiver bm *Bitmap 接受者bitmap的指针 +//@param num int 待插入的位的下标 +//@return nil +func (bm *Bitmap) Insert(num uint) { + //bm不存在时直接结束 + if bm == nil { + return + } + //开始插入 + if num/64+1 > uint(len(bm.bits)) { + //当前冗余量小于num位,需要扩增 + var tmp []uint64 + //通过冗余扩增减少扩增次数 + if num/64+1 < uint(len(bm.bits)+1024) { + //入的位比冗余的多不足2^16即1024*64时,则新增1024个uint64 + tmp = make([]uint64, len(bm.bits)+1024) + } else { + //直接增加到可以容纳第num位的位置 + tmp = make([]uint64, num/64+1) + } + //将原有元素复制到新增的切片内,并将bm所指向的修改为扩增后的 + copy(tmp, bm.bits) + bm.bits = tmp + } + //将第num位设为1即实现插入 + bm.bits[num/64] ^= 1 << (num % 64) +} + +//@title Delete +//@description +// 以bitmap位图容器做接收者 +// 向位图中第num位删除一个元素(下标从0开始) +// 当num大于当前所能存储的位范围时,直接结束即可 +// 删除完成后对切片最后存储的uint64进行判断是否大于1,若大于1则不做缩容 +// 若等于0则可以进行缩容 +// 对于缩容而言,从后往前遍历判断最后有多少个连续的0,即可以删除的多少组 +// 若可删除的组大于总组数的一半则进行删除,否则则当作冗余量即可 +// 若可删除的组数超过1024个时,则先删除1024个 +//@receiver bm *Bitmap 接受者bitmap的指针 +//@param num int 待删除的位的下标 +//@return nil +func (bm *Bitmap) Delete(num uint) { + //bm不存在时直接结束 + if bm == nil { + return + } + //num超出范围,直接结束 + if num/64+1 > uint(len(bm.bits)) { + return + } + //将第num位设为0 + bm.bits[num/64] &^= 1 << (num % 64) + if bm.bits[len(bm.bits)-1] == 0 { + //最后一组为0,可能进行缩容 + //从后往前遍历判断可缩容内容是否小于总组数 + i := len(bm.bits) - 1 + for ; i >= 0; i-- { + if bm.bits[i] == 0 && i != len(bm.bits)-256 { + continue + } else { + //不为0或到1024个时即可返回 + break + } + } + if i <= len(bm.bits)/2 || i == len(bm.bits)-256 { + //小于总组数一半或超过1023个,进行缩容 + bm.bits = bm.bits[:i+1] + } + } else { + return + } +} + +//@title Check +//@description +// 以bitmap位图容器做接收者 +// 检验第num位在位图中是否存在 +// 当num大于当前所能存储的位范围时,直接返回false +// 否则判断第num为是否为1,为1返回true,否则返回false +//@receiver bm *Bitmap 接受者bitmap的指针 +//@param num int 待检测位的下标 +//@return b bool 第num位存在于位图中吗? +func (bm *Bitmap) Check(num uint) (b bool) { + //bm不存在时直接返回false并结束 + if bm == nil { + return false + } + //num超出范围,直接返回false并结束 + if num/64+1 > uint(len(bm.bits)) { + return false + } + //判断第num是否为1,为1返回true,否则为false + if bm.bits[num/64]&(1<<(num%64)) > 0 { + return true + } + return false +} + +//@title All +//@description +// 以bitmap位图容器做接收者 +// 返回所有在位图中存在的元素的下标 +// 返回的下标是单调递增序列 +//@receiver bm *Bitmap 接受者bitmap的指针 +//@param nil +//@return nums []uint 所有在位图中存在的元素的下标集合 +func (bm *Bitmap) All() (nums []uint) { + //对要返回的集合进行初始化,以避免返回nil + nums = make([]uint, 0, 0) + //bm不存在时直接返回并结束 + if bm == nil { + return nums + } + //分组遍历判断某下标的元素是否存在于位图中,即其值是否为1 + for j := 0; j < len(bm.bits); j++ { + for i := 0; i < 64; i++ { + if bm.bits[j]&(1< 0 { + //该元素存在,添加入结果集合内 + nums = append(nums, uint(j*64+i)) + } + } + } + return nums +} + +//@title Clear +//@description +// 以bitmap位图容器做接收者 +// 清空位图 +//@receiver bm *Bitmap 接受者bitmap的指针 +//@param nil +//@return nil +func (bm *Bitmap) Clear() { + if bm == nil { + return + } + bm.bits = make([]uint64, 0, 0) +} diff --git a/data_structure/bloomFilter/bloomFilter.go b/data_structure/bloomFilter/bloomFilter.go new file mode 100644 index 0000000..ed0010f --- /dev/null +++ b/data_structure/bloomFilter/bloomFilter.go @@ -0,0 +1,145 @@ +package bloomFilter + +//@Title bloomFilter +//@Description +// bloomFilter布隆过滤器容器包 +// 内部使用uint64切片进行存储 +// 将任意类型的值进行hash计算后放入布隆过滤器中 +// 可用于查找某一值是否已经插入过,但查找存在误差,只能确定其不存在,不能保证其必然存在 +// 不能用于删除某一特定值,但可清空整个布隆过滤器 + +import "fmt" + +//bloomFilter布隆过滤器结构体 +//包含其用于存储的uint64元素切片 +//选用uint64是为了更多的利用bit位 +type bloomFilter struct { + bits []uint64 + hash Hash +} + +//bloomFilter布隆过滤器接口 +//存放了bloomFilter布隆过滤器可使用的函数 +//对应函数介绍见下方 +type bloomFilteror interface { + Insert(v interface{}) //向布隆过滤器中插入v + Check(v interface{}) (b bool) //检查该值是否存在于布隆过滤器中,该校验存在误差 + Clear() //清空该布隆过滤器 +} + +//允许自行传入hash函数 +type Hash func(v interface{}) (h uint32) + +//@title hash +//@description +// 传入一个虚拟节点id和实际结点 +// 计算出它的hash值 +// 逐层访问并利用素数131计算其hash值随后返回 +//@receiver nil +//@param v interface{} 待计算的值 +//@return h uint32 计算得到的hash值 +func hash(v interface{}) (h uint32) { + h = uint32(0) + s := fmt.Sprintf("131-%v-%v", v,v) + bs := []byte(s) + for i := range bs { + h += uint32(bs[i]) * 131 + } + return h +} + +//@title New +//@description +// 新建一个bloomFilter布隆过滤器容器并返回 +// 初始bloomFilter的切片数组为空 +//@receiver nil +//@param h Hash hash函数 +//@return bf *bloomFilter 新建的bloomFilter指针 +func New(h Hash) (bf *bloomFilter) { + if h == nil { + h = hash + } + return &bloomFilter{ + bits: make([]uint64, 0, 0), + hash: h, + } +} + +//@title Insert +//@description +// 以bloomFilter布隆过滤器容器做接收者 +// 先将待插入的value计算得到其哈希值hash +// 再向布隆过滤器中第hash位插入一个元素(下标从0开始) +// 当hash大于当前所能存储的位范围时,需要进行扩增 +// 若要插入的位比冗余的多不足2^16即1024*64时,则新增1024个uint64 +// 否则则直接增加到可以容纳第hash位的位置,以此可以提高冗余量,避免多次增加 +//@receiver bf *bloomFilter 接收者bloomFilter指针 +//@param v interface{} 待插入的值 +//@return nil +func (bf *bloomFilter) Insert(v interface{}) { + //bm不存在时直接结束 + if bf == nil { + return + } + //开始插入 + h := bf.hash(v) + if h/64+1 > uint32(len(bf.bits)) { + //当前冗余量小于num位,需要扩增 + var tmp []uint64 + //通过冗余扩增减少扩增次数 + if h/64+1 < uint32(len(bf.bits)+1024) { + //入的位比冗余的多不足2^16即1024*64时,则新增1024个uint64 + tmp = make([]uint64, len(bf.bits)+1024) + } else { + //直接增加到可以容纳第num位的位置 + tmp = make([]uint64, h/64+1) + } + //将原有元素复制到新增的切片内,并将bm所指向的修改为扩增后的 + copy(tmp, bf.bits) + bf.bits = tmp + } + //将第num位设为1即实现插入 + bf.bits[h/64] ^= 1 << (h % 64) +} + +//@title Check +//@description +// 以bloomFilter布隆过滤器容器做接收者 +// 将待查找的值做哈希计算得到哈希值h +// 检验第h位在位图中是否存在 +// 当h大于当前所能存储的位范围时,直接返回false +// 否则判断第h为是否为1,为1返回true,否则返回false +// 利用布隆过滤器做判断存在误差,即返回true可能也不存在,但返回false则必然不存在 +//@receiver bf *bloomFilter 接收者bloomFilter指针 +//@param v interface{} 待查找的值 +//@return b bool 待查找的值可能存在于布隆过滤器中吗? +func (bf *bloomFilter) Check(v interface{}) (b bool) { + //bf不存在时直接返回false并结束 + if bf == nil { + return false + } + h := bf.hash(v) + //h超出范围,直接返回false并结束 + if h/64+1 > uint32(len(bf.bits)) { + return false + } + //判断第num是否为1,为1返回true,否则为false + if bf.bits[h/64]&(1<<(h%64)) > 0 { + return true + } + return false +} + +//@title Clear +//@description +// 以bloomFilter布隆过滤器容器做接收者 +// 清空整个布隆过滤器 +//@receiver bf *bloomFilter 接收者bloomFilter指针 +//@param nil +//@return nums []uint 所有在位图中存在的元素的下标集合 +func (bf *bloomFilter) Clear() { + if bf == nil { + return + } + bf.bits = make([]uint64, 0, 0) +} diff --git a/data_structure/bsTree/bsTree.go b/data_structure/bsTree/bsTree.go new file mode 100644 index 0000000..605a14b --- /dev/null +++ b/data_structure/bsTree/bsTree.go @@ -0,0 +1,239 @@ +package bsTree + +//@Title bsTree +//@Description +// 二叉搜索树-Binary Search Tree +// 以二叉树的形式实现 +// 二叉树实例保存根节点和比较器以及保存的数量 +// 可以在创建时设置节点是否可重复 +// 若节点可重复则增加节点中的数值,否则对节点存储元素进行覆盖 +// 二叉搜索树不进行平衡 +// 增加互斥锁实现并发控制 + +import ( + "github.com/hlccd/goSTL/utils/comparator" + "github.com/hlccd/goSTL/utils/iterator" + "sync" +) + +//bsTree二叉搜索树结构体 +//该实例存储二叉树的根节点 +//同时保存该二叉树已经存储了多少个元素 +//二叉树中排序使用的比较器在创建时传入,若不传入则在插入首个节点时从默认比较器中寻找 +//创建时传入是否允许该二叉树出现重复值,如果不允许则进行覆盖,允许则对节点数目增加即可 +type BsTree struct { + root *node //根节点指针 + size uint64 //存储元素数量 + cmp comparator.Comparator //比较器 + isMulti bool //是否允许重复 + mutex sync.Mutex //并发控制锁 +} + +//bsTree二叉搜索树容器接口 +//存放了bsTree二叉搜索树可使用的函数 +//对应函数介绍见下方 +type bsTreeer interface { + Iterator() (i *Iterator.Iterator) //返回包含该二叉树的所有元素,重复则返回多个 + Size() (num uint64) //返回该二叉树中保存的元素个数 + Clear() //清空该二叉树 + Empty() (b bool) //判断该二叉树是否为空 + Insert(e interface{}) //向二叉树中插入元素e + Erase(e interface{}) //从二叉树中删除元素e + Count(e interface{}) (num uint64) //从二叉树中寻找元素e并返回其个数 +} + +//@title New +//@description +// 新建一个bsTree二叉搜索树容器并返回 +// 初始根节点为nil +// 传入该二叉树是否为可重复属性,如果为true则保存重复值,否则对原有相等元素进行覆盖 +// 若有传入的比较器,则将传入的第一个比较器设为该二叉树的比较器 +//@receiver nil +//@param isMulti bool 该二叉树是否保存重复值? +//@param Cmp ...comparator.Comparator bsTree比较器集 +//@return bs *BsTree 新建的bsTree指针 +func New(isMulti bool, Cmp ...comparator.Comparator) (bs *BsTree) { + //判断是否有传入比较器,若有则设为该二叉树默认比较器 + var cmp comparator.Comparator + if len(Cmp) == 0 { + cmp = nil + } else { + cmp = Cmp[0] + } + return &BsTree{ + root: nil, + size: 0, + cmp: cmp, + isMulti: isMulti, + mutex: sync.Mutex{}, + } +} + +//@title Iterator +//@description +// 以bsTree二叉搜索树做接收者 +// 将该二叉树中所有保存的元素将从根节点开始以中缀序列的形式放入迭代器中 +// 若允许重复存储则对于重复元素进行多次放入 +//@receiver bt *BsTree 接受者bsTree的指针 +//@param nil +//@return i *iterator.Iterator 新建的Iterator迭代器指针 +func (bs *BsTree) Iterator() (i *Iterator.Iterator) { + if bs == nil { + //创建一个允许插入重复值的二叉搜 + bs = New(true) + } + bs.mutex.Lock() + es := bs.root.inOrder() + i = Iterator.New(&es) + bs.mutex.Unlock() + return i +} + +//@title Size +//@description +// 以bsTree二叉搜索树做接收者 +// 返回该容器当前含有元素的数量 +// 如果容器为nil则创建一个并返回其承载的元素个数 +//@receiver bt *BsTree 接受者bsTree的指针 +//@param nil +//@return num uint64 容器中实际使用元素所占空间大小 +func (bs *BsTree) Size() (num uint64) { + if bs == nil { + //创建一个允许插入重复值的二叉搜 + bs = New(true) + } + return bs.size +} + +//@title Clear +//@description +// 以bsTree二叉搜索树做接收者 +// 将该容器中所承载的元素清空 +// 将该容器的size置0 +//@receiver bt *BsTree 接受者bsTree的指针 +//@param nil +//@return nil +func (bs *BsTree) Clear() { + if bs == nil { + //创建一个允许插入重复值的二叉搜 + bs = New(true) + } + bs.mutex.Lock() + bs.root = nil + bs.size = 0 + bs.mutex.Unlock() +} + +//@title Empty +//@description +// 以bsTree二叉搜索树做接收者 +// 判断该二叉搜索树是否含有元素 +// 如果含有元素则不为空,返回false +// 如果不含有元素则说明为空,返回true +// 如果容器不存在,返回true +//@receiver bt *BsTree 接受者bsTree的指针 +//@param nil +//@return b bool 该容器是空的吗? +func (bs *BsTree) Empty() (b bool) { + if bs == nil { + //创建一个允许插入重复值的二叉搜 + bs = New(true) + } + return bs.size == 0 +} + +//@title Insert +//@description +// 以bsTree二叉搜索树做接收者 +// 向二叉树插入元素e,若不允许重复则对相等元素进行覆盖 +// 如果二叉树为空则之间用根节点承载元素e,否则以根节点开始进行查找 +// 不做平衡 +//@receiver bt *BsTree 接受者bsTree的指针 +//@param e interface{} 待插入元素 +//@return nil +func (bs *BsTree) Insert(e interface{}) { + if bs == nil { + //创建一个允许插入重复值的二叉搜 + bs = New(true) + } + bs.mutex.Lock() + if bs.Empty() { + //二叉树为空,用根节点承载元素e + if bs.cmp == nil { + bs.cmp = comparator.GetCmp(e) + } + if bs.cmp == nil { + bs.mutex.Unlock() + return + } + bs.root = newNode(e) + bs.size++ + bs.mutex.Unlock() + return + } + //二叉树不为空,从根节点开始查找添加元素e + if bs.root.insert(e, bs.isMulti, bs.cmp) { + bs.size++ + } + bs.mutex.Unlock() +} + +//@title Erase +//@description +// 以bsTree二叉搜索树做接收者 +// 从搜素二叉树中删除元素e +// 若允许重复记录则对承载元素e的节点中数量记录减一即可 +// 若不允许重复记录则删除该节点同时将前缀节点或后继节点更换过来以保证二叉树的不发送断裂 +// 如果该二叉树仅持有一个元素且根节点等价于待删除元素,则将二叉树根节点置为nil +//@receiver bt *BsTree 接受者bsTree的指针 +//@param e interface{} 待删除元素 +//@return nil +func (bs *BsTree) Erase(e interface{}) { + if bs == nil { + //创建一个允许插入重复值的二叉搜 + bs = New(true) + } + if bs.size == 0 { + return + } + bs.mutex.Lock() + if bs.size == 1 && bs.cmp(bs.root.value, e) == 0 { + //二叉树仅持有一个元素且根节点等价于待删除元素,将二叉树根节点置为nil + bs.root = nil + bs.size = 0 + bs.mutex.Unlock() + return + } + //从根节点开始删除元素e + //如果删除成功则将size-1 + if bs.root.delete(e, bs.isMulti, bs.cmp) { + bs.size-- + } + bs.mutex.Unlock() +} + +//@title Count +//@description +// 以bsTree二叉搜索树做接收者 +// 从搜素二叉树中查找元素e的个数 +// 如果找到则返回该二叉树中和元素e相同元素的个数 +// 如果不允许重复则最多返回1 +// 如果未找到则返回0 +//@receiver bt *BsTree 接受者bsTree的指针 +//@param e interface{} 待查找元素 +//@return num uint64 待查找元素在二叉树中存储的个数 +func (bs *BsTree) Count(e interface{}) (num uint64) { + if bs == nil { + //二叉树不存在,返回0 + return 0 + } + if bs.Empty() { + //二叉树为空,返回0 + return 0 + } + bs.mutex.Lock() + //从根节点开始查找并返回查找结果 + num = bs.root.search(e, bs.isMulti, bs.cmp) + bs.mutex.Unlock() + return num +} diff --git a/data_structure/bsTree/node.go b/data_structure/bsTree/node.go new file mode 100644 index 0000000..3089187 --- /dev/null +++ b/data_structure/bsTree/node.go @@ -0,0 +1,230 @@ +package bsTree + +//@Title bsTree +//@Description +// 二叉搜索树的节点 +// 可通过节点实现二叉搜索树的添加删除 +// 也可通过节点返回整个二叉搜索树的所有元素 + +import "github.com/hlccd/goSTL/utils/comparator" + +//node树节点结构体 +//该节点是二叉搜索树的树节点 +//若该二叉搜索树允许重复则对节点num+1即可,否则对value进行覆盖 +//二叉搜索树节点不做平衡 +type node struct { + value interface{} //节点中存储的元素 + num uint64 //该元素数量 + left *node //左节点指针 + right *node //右节点指针 +} + +//@title newNode +//@description +// 新建一个二叉搜索树节点并返回 +// 将传入的元素e作为该节点的承载元素 +// 该节点的num默认为1,左右子节点设为nil +//@receiver nil +//@param e interface{} 承载元素e +//@return n *node 新建的二叉搜索树节点的指针 +func newNode(e interface{}) (n *node) { + return &node{ + value: e, + 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 := uint64(0); i < n.num; i++ { + es = append(es, n.value) + } + if n.right != nil { + es = append(es, n.right.inOrder()...) + } + return es +} + +//@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) (b bool) { + if n == nil { + return false + } + //n中承载元素小于e,从右子树继续插入 + if cmp(n.value, e) < 0 { + if n.right == nil { + //右子树为nil,直接插入右子树即可 + n.right = newNode(e) + return true + } else { + return n.right.insert(e, isMulti, cmp) + } + } + //n中承载元素大于e,从左子树继续插入 + if cmp(n.value, e) > 0 { + if n.left == nil { + //左子树为nil,直接插入左子树即可 + n.left = newNode(e) + return true + } else { + return n.left.insert(e, isMulti, cmp) + } + } + //n中承载元素等于e + if isMulti { + //允许重复 + n.num++ + return true + } + //不允许重复,直接进行覆盖 + n.value = e + 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) + } + //n中承载元素等于e + if (*n).num > 1 && isMulti { + //允许重复且个数超过1,则减少num即可 + (*n).num-- + return true + } + if n.left == nil && n.right == nil { + //该节点无前缀节点和后继节点,删除即可 + *(&n) = nil + return true + } + if n.left != nil { + //该节点有前缀节点,找到前缀节点进行交换并删除即可 + ln := n.left + if ln.right == nil { + n.value = ln.value + n.num = ln.num + n.left = ln.left + } else { + for ln.right.right != nil { + ln = ln.right + } + n.value = ln.right.value + n.num = ln.right.num + ln.right = ln.right.left + } + } else if (*n).right != nil { + //该节点有后继节点,找到后继节点进行交换并删除即可 + tn := n.right + if tn.left == nil { + n.value = tn.value + n.num = tn.num + n.right = tn.right + } else { + for tn.left.left != nil { + tn = tn.left + } + n.value = tn.left.value + n.num = tn.left.num + tn.left = tn.left.right + } + return true + } + 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 uint64 待查找元素在二叉树中存储的数量 +func (n *node) search(e interface{}, isMulti bool, cmp comparator.Comparator) (num uint64) { + if n == nil { + return 0 + } + //n中承载元素小于e,从右子树继续查找并返回结果 + if cmp(n.value, e) < 0 { + return n.right.search(e, isMulti, cmp) + } + //n中承载元素大于e,从左子树继续查找并返回结果 + if cmp(n.value, e) > 0 { + return n.left.search(e, isMulti, cmp) + } + //n中承载元素等于e,直接返回结果 + return n.num +} diff --git a/data_structure/cbTree/cbTree.go b/data_structure/cbTree/cbTree.go new file mode 100644 index 0000000..ab3a7cb --- /dev/null +++ b/data_structure/cbTree/cbTree.go @@ -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 +} diff --git a/data_structure/cbTree/node.go b/data_structure/cbTree/node.go new file mode 100644 index 0000000..d8aa4d9 --- /dev/null +++ b/data_structure/cbTree/node.go @@ -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 + } +} diff --git a/data_structure/consistentHash/consistentHash.go b/data_structure/consistentHash/consistentHash.go new file mode 100644 index 0000000..440b92c --- /dev/null +++ b/data_structure/consistentHash/consistentHash.go @@ -0,0 +1,329 @@ +package consistentHash + +//@Title consistentHash +//@Description +// 一致性哈希-consistent hash +// 一致性hash主要用以解决当出现增删结点时需要重新计算hash值的情况 +// 同时,利用虚拟结点解决了数据倾斜的问题 +// hash范围为2^32,即一个uint32的全部范围 +// 本次实现中不允许出现hash值相同的点,出现时则舍弃 +// 虚拟结点最多有32个,最少数量可由用户自己决定,但不得低于1个 +// 使用互斥锁实现并发控制 +import ( + "fmt" + "sync" +) + +//最大虚拟节点数量 +const ( + maxReplicas = 32 +) + +//素数表 +//用以减少hash冲突 +var primes = []uint32{3, 5, 7, 11, 13, 17, 19, 23, 29, 31, + 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, + 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, + 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, + 121, 191, 193, 197, 199, 211, 223, 227, 229, 233, + 239, 241, 251, +} + +//一致性hash结构体 +//该实例了一致性hash在创建时设定的最小虚拟节点数 +//同时保存了所有虚拟节点的hash值 +//建立了虚拟节点hash值与实际结点之间的映射表 +//每个实际结点也可以映射其所有的虚拟节点的hash值 +//并发控制锁用以保证线程安全 +type ConsistentHash struct { + minReplicas int //最小的虚拟节点数 + keys []uint32 //存储的结点和虚拟结点的集合 + hashMap map[uint32]interface{} //hash与结点之间的映射 + nodeMap map[interface{}][]uint32 //结点所对应的虚拟节点的hash值 + mutex sync.Mutex //并发控制锁 +} + +type consistentHasher interface { + Size() (num int) //返回一致性hash中的虚拟节点数量 + Clear() //清空一致性hash的所有结点 + Empty() (b bool) //返回该一致性hash是否有结点存在 + Insert(keys ...interface{}) (nums []int) //向该一致性hash中插入一组结点,同时返回其生成的虚拟节点的数量 + Erase(key interface{}) (ok bool) //删除结点key + Get(key interface{}) (ans interface{}) //查找key对应的结点 +} + +//@title hash +//@description +// 传入一个虚拟节点id和实际结点 +// 计算出它的hash值 +// 先利用id从素数表中找到对应的素数,然后将id,素数和实际结点转化为[]byte +// 逐层访问并利用素数计算其hash值随后返回 +//@receiver nil +//@param id int 虚拟节点的id +//@param v interface{} 实际结点的key +//@return h uint32 计算得到的hash值 +func hash(id int, v interface{}) (h uint32) { + prime := primes[(id*id+len(primes))%len(primes)] + h = uint32(0) + s := fmt.Sprintf("%d-%v-%d", id*int(prime), v, prime) + bs := []byte(s) + for i := range bs { + h += uint32(bs[i]) * prime + } + return h +} + +//新建一个一致性hash结构体指针并返回 +//传入其设定的最小的虚拟节点数量 + +//@title New +//@description +// 新建一个一致性hash结构体指针并返回 +// 传入设定的最少虚拟节点数量,不可小于1也不可大于最大虚拟节点数 +//@receiver nil +//@param minReplicas int hashMap的hash函数集 +//@return ch *ConsistentHash 新建的一致性hash指针 +func New(minReplicas int) (ch *ConsistentHash) { + if minReplicas > maxReplicas { + //超过最大虚拟节点数 + minReplicas = maxReplicas + } + if minReplicas < 1 { + //最少虚拟节点数量不得小于1 + minReplicas = 1 + } + ch = &ConsistentHash{ + minReplicas: minReplicas, + keys: make([]uint32, 0, 0), + hashMap: make(map[uint32]interface{}), + nodeMap: make(map[interface{}][]uint32), + mutex: sync.Mutex{}, + } + return ch +} + +//@title Size +//@description +// 以一致性hash做接收者 +// 返回该容器当前含有的虚拟结点数量 +// 如果容器为nil返回0 +//@receiver ch *ConsistentHash 接受者一致性hash的指针 +//@param nil +//@return num int 当前含有的虚拟结点数量 +func (ch *ConsistentHash) Size() (num int) { + if ch == nil { + return 0 + } + return len(ch.keys) +} + +//@title Clear +//@description +// 以一致性hash做接收者 +// 将该容器中所承载的所有结点清除 +// 被清除结点包括实际结点和虚拟节点 +// 重建映射表 +//@receiver ch *ConsistentHash 接受者一致性hash的指针 +//@param nil +//@return nil +func (ch *ConsistentHash) Clear() { + if ch == nil { + return + } + ch.mutex.Lock() + //重建vector并扩容到16 + ch.keys = make([]uint32, 0, 0) + ch.hashMap = make(map[uint32]interface{}) + ch.nodeMap = make(map[interface{}][]uint32) + ch.mutex.Unlock() +} + +//@title Empty +//@description +// 以一致性hash做接收者 +// 判断该一致性hash中是否含有元素 +// 如果含有结点则不为空,返回false +// 如果不含有结点则说明为空,返回true +// 如果容器不存在,返回true +//@receiver ch *ConsistentHash 接受者一致性hash的指针 +//@param nil +//@return b bool 该容器是空的吗? +func (ch *ConsistentHash) Empty() (b bool) { + if ch == nil { + return false + } + return len(ch.keys) > 0 +} + +//@title Insert +//@description +// 以一致性hash做接收者 +// 向一致性hash中插入结点,同时返回每一个结点插入的数量 +// 插入每个结点后将其对应的虚拟节点的hash放入映射表内和keys内 +// 对keys做排序,利用二分排序算法 +//@receiver ch *ConsistentHash 接受者一致性hash的指针 +//@param keys ...interface{} 待插入的结点的集合 +//@return nums []int 插入结点所生成的虚拟节点数量的集合 +func (ch *ConsistentHash) Insert(keys ...interface{}) (nums []int) { + nums = make([]int, 0, len(keys)) + ch.mutex.Lock() + //遍历所有待插入的结点 + for _, key := range keys { + num := 0 + //判断结点是否已经存在 + _, exist := ch.nodeMap[key] + if !exist { + //结点不存在,开始插入 + for i := 0; i < maxReplicas || num < ch.minReplicas; i++ { + //生成每个虚拟节点的hash值 + h := uint32(hash(i, key)) + //判断生成的hash值是否存在,存在则不插入 + _, ok := ch.hashMap[h] + if !ok { + //hash值不存在,进行插入 + num++ + ch.keys = append(ch.keys, h) + //同时建立hash值和结点之间的映射关系 + ch.hashMap[h] = key + ch.nodeMap[key] = append(ch.nodeMap[key], h) + } + } + } + nums = append(nums, num) + } + //对keys进行排序,以方便后续查找 + ch.sort(0, len(ch.keys)-1) + ch.mutex.Unlock() + return nums +} + +//@title sort +//@description +// 以一致性hash做接收者 +// 二分排序 +// 主要用于一致性hash的keys的排序 +// 以保证其有序性 +// 同时方便后续使用二分查找 +//@receiver ch *ConsistentHash 接受者一致性hash的指针 +//@param L int 左下标 +//@param R int 右下标 +//@return nil +func (ch *ConsistentHash) sort(L, R int) { + if L >= R { + //左下标大于右下标,结束 + return + } + //找到中间结点,从左右两侧以双指针形式向中间靠近 + l, r, m := L-1, R+1, ch.keys[(L+R)/2] + for l < r { + //左侧出现不小于中间结点时停下 + l++ + for ch.keys[l] < m { + l++ + } + //右侧出现不大于中间结点时停下 + r-- + for ch.keys[r] > m { + r-- + } + if l < r { + //左节点仍在右结点左方,交换结点的值 + ch.keys[l], ch.keys[r] = ch.keys[r], ch.keys[l] + } + } + //递归排序左右两侧保证去有序性 + ch.sort(L, l-1) + ch.sort(r+1, R) +} + +//@title Erase +//@description +// 以一致性hash做接收者 +// 删除以key为索引的结点 +// 先利用结点映射表判断该key是否存在于一致性hash内 +// 若存在则从映射表内删除 +// 同时找到其所有的虚拟节点的hash值 +// 遍历keys进行删除 +//@receiver ch *ConsistentHash 接受者一致性hash的指针 +//@param key interface{} 待删除元素的key +//@return b bool 删除成功? +func (ch *ConsistentHash) Erase(key interface{}) (ok bool) { + ch.mutex.Lock() + hs, ok := ch.nodeMap[key] + if ok { + //该结点存在于一致性hash内 + //删除该结点 + delete(ch.nodeMap, key) + //删除所有该结点的虚拟节点与该结点的映射关系 + for i := range hs { + delete(ch.hashMap, hs[i]) + } + //将待删除的虚拟结点删除即可 + arr := make([]uint32, 0, len(ch.keys)-len(hs)) + for i := range ch.keys { + h := ch.keys[i] + flag := true + for j := range hs { + if hs[j] == h { + flag = false + } + } + if flag { + arr = append(arr, h) + } + } + ch.keys = arr + } + ch.mutex.Unlock() + return ok +} + +//@title Get +//@description +// 以一致性hash做接收者 +// 从一致性hash中获取以key为索引的下一个结点的索引 +// 只要一致性hash内存储了结点则必然可以找到 +// 将keys看成一个环 +// 要找的key的计算出hash后放入环中 +// 按顺时针向下找直到遇到第一个虚拟节点 +// 寻找过程利用二分,若二分找到的结点为末尾结点的下一个,即为首个虚拟节点 +//@receiver ch *ConsistentHash 接受者一致性hash的指针 +//@param key interface{} 待查找的结点 +//@return ans interface{} 找到的对应节点 +func (ch *ConsistentHash) Get(key interface{}) (ans interface{}) { + if len(ch.keys) == 0 { + return nil + } + ch.mutex.Lock() + //计算key的hash值 + h := hash(0, key) + //从现存的所有虚拟结点中找到该hash值对应的下一个虚拟节点对应的结点的索引 + idx := ch.search(h) + ans = ch.hashMap[ch.keys[idx]] + ch.mutex.Unlock() + return ans +} + +//@title search +//@description +// 以一致性hash做接收者 +// 二分查找 +// 找到最近的不小于该值的hash值 +// 如果不存在则返回0,即进行取模运算即可 +//@receiver ch *ConsistentHash 接受者一致性hash的指针 +//@param h uint32 待查找结点的hash值 +//@return idx uint32 找到的对应虚拟节点的下标 +func (ch *ConsistentHash) search(h uint32) (idx uint32) { + //二分查找,寻找不小于该hash值的下一个值的下标 + l, m, r := uint32(0), uint32(len(ch.keys)/2), uint32(len(ch.keys)) + for l < r { + m = (l + r) / 2 + if ch.keys[m] >= h { + r = m + } else { + l = m + 1 + } + } + //当找到的下标等同于keys的长度时即为0 + return l % uint32(len(ch.keys)) +} diff --git a/data_structure/deque/deque.go b/data_structure/deque/deque.go new file mode 100644 index 0000000..9575028 --- /dev/null +++ b/data_structure/deque/deque.go @@ -0,0 +1,272 @@ +package deque + +//@Title deque +//@Description +// deque双队列容器包 +// 区别于queue的动态数组实现方式,deque采取将数组和链表相结合的方案 +// 该容器既可以在首部增删元素,也可以在尾部增删元素 +// deque在扩容和缩容时,都是固定增加2^10的空间,同时这一部分空间形成链表节点,并串成链表去保存 +// 可接纳不同类型的元素 +// 通过并发控制锁保证了在高并发过程中的数据一致性 + +import ( + "github.com/hlccd/goSTL/utils/iterator" + "sync" +) + +//deque双向队列结构体 +//包含链表的头尾节点指针 +//当删除节点时通过头尾节点指针进入链表进行删除 +//当一个节点全部被删除后则释放该节点,同时首尾节点做相应调整 +//当添加节点时若未占满节点空间时移动下标并做覆盖即可 +//当添加节点时空间已使用完毕时,根据添加位置新建一个新节点补充上去 +type Deque struct { + first *node //链表首节点指针 + last *node //链表尾节点指针 + size uint64 //当前存储的元素个数 + mutex sync.Mutex //并发控制锁 +} + +//deque双向队列容器接口 +//存放了deque容器可使用的函数 +//对应函数介绍见下方 + +type dequer interface { + Iterator() (i *Iterator.Iterator) //返回包含双向队列中所有元素的迭代器 + Size() (size uint64) //返回该双向队列中元素的使用空间大小 + Clear() //清空该双向队列 + Empty() (b bool) //判断该双向队列是否为空 + PushFront(e interface{}) //将元素e添加到该双向队列的首部 + PushBack(e interface{}) //将元素e添加到该双向队列的尾部 + PopFront() (e interface{}) //将该双向队列首元素弹出 + PopBack() (e interface{}) //将该双向队列首元素弹出 + Front() (e interface{}) //获取该双向队列首部元素 + Back() (e interface{}) //获取该双向队列尾部元素 +} + +//@title New +//@description +// 新建一个deque双向队列容器并返回 +// 初始deque双向队列的链表首尾节点为nil +// 初始size为0 +//@receiver nil +//@param nil +//@return d *Deque 新建的deque指针 +func New() *Deque { + return &Deque{ + first: nil, + last: nil, + size: 0, + mutex: sync.Mutex{}, + } +} + +//@title Iterator +//@description +// 以deque双向队列容器做接收者 +// 将deque双向队列容器中所承载的元素放入迭代器中 +// 节点的冗余空间不释放 +//@receiver d *Deque 接收者的deque指针 +//@param nil +//@return i *iterator.Iterator 新建的Iterator迭代器指针 +func (d *Deque) Iterator() (i *Iterator.Iterator) { + if d == nil { + d = New() + } + tmp := make([]interface{}, 0, d.size) + //遍历链表的所有节点,将其中承载的元素全部复制出来 + for m := d.first; m != nil; m = m.nextNode() { + tmp = append(tmp, m.value()...) + } + return Iterator.New(&tmp) +} + +//@title Size +//@description +// 以deque双向队列容器做接收者 +// 返回该容器当前含有元素的数量 +// 该长度并非实际占用空间数量 +// 若容器为空则返回0 +//@receiver d *Deque 接收者的deque指针 +//@param nil +//@return size uint64 容器中实际使用元素所占空间大小 +func (d *Deque) Size() (size uint64) { + if d == nil { + d = New() + } + return d.size +} + +//@title Clear +//@description +// 以deque双向队列容器做接收者 +// 将该容器中所承载的元素清空 +// 将该容器的首尾指针均置nil,将size重置为0 +//@receiver d *Deque 接收者的deque指针 +//@param nil +//@return nil +func (d *Deque) Clear() { + if d == nil { + d = New() + return + } + d.mutex.Lock() + d.first = nil + d.last = nil + d.size = 0 + d.mutex.Unlock() +} + +//@title Empty +//@description +// 以deque双向队列容器做接收者 +// 判断该deque双向队列容器是否含有元素 +// 如果含有元素则不为空,返回false +// 如果不含有元素则说明为空,返回true +// 如果容器不存在,返回true +// 该判断过程通过size进行判断,为0则为true,否则为false +//@receiver d *Deque 接收者的deque指针 +//@param nil +//@return b bool 该容器是空的吗? +func (d *Deque) Empty() (b bool) { + if d == nil { + d = New() + } + return d.Size() == 0 +} + +//@title PushFront +//@description +// 以deque双向队列向量容器做接收者 +// 在容器首部插入元素 +// 通过链表首节点进行添加 +//@receiver d *Deque 接收者的deque指针 +//@param e interface{} 待插入元素 +//@return nil +func (d *Deque) PushFront(e interface{}) { + if d == nil { + d = New() + } + d.mutex.Lock() + d.size++ + //通过首节点进行添加 + if d.first == nil { + d.first = createFirst() + d.last = d.first + } + d.first = d.first.pushFront(e) + d.mutex.Unlock() +} + +//@title PushBack +//@description +// 以deque双向队列向量容器做接收者 +// 在容器尾部插入元素 +// 通过链表尾节点进行添加 +//@receiver d *Deque 接收者的deque指针 +//@param e interface{} 待插入元素 +//@return nil +func (d *Deque) PushBack(e interface{}) { + if d == nil { + d = New() + } + d.mutex.Lock() + d.size++ + //通过尾节点进行添加 + if d.last == nil { + d.last = createLast() + d.first = d.last + } + d.last = d.last.pushBack(e) + d.mutex.Unlock() +} + +//@title PopFront +//@description +// 以deque双向队列容器做接收者 +// 利用首节点进行弹出元素,可能存在首节点全部释放要进行首节点后移的情况 +// 当元素全部删除后,释放全部空间,将首尾节点都设为nil +//@receiver d *Deque 接收者的deque指针 +//@param nil +//@return e interface{} 首元素 +func (d *Deque) PopFront() (e interface{}) { + if d == nil { + d = New() + } + if d.size == 0 { + return nil + } + d.mutex.Lock() + //利用首节点删除首元素 + //返回新的首节点 + e = d.first.front() + d.first = d.first.popFront() + d.size-- + if d.size == 0 { + //全部删除完成,释放空间,并将首尾节点设为nil + d.first = nil + d.last = nil + } + d.mutex.Unlock() + return e +} + +//@title PopBack +//@description +// 以deque双向队列容器做接收者 +// 利用尾节点进行弹出元素,可能存在尾节点全部释放要进行尾节点前移的情况 +// 当元素全部删除后,释放全部空间,将首尾节点都设为nil +//@receiver d *Deque 接收者的deque指针 +//@param nil +//@return e interface{} 尾元素 +func (d *Deque) PopBack() (e interface{}) { + if d == nil { + d = New() + } + if d.size == 0 { + return nil + } + d.mutex.Lock() + //利用尾节点删除首元素 + //返回新的尾节点 + d.last = d.last.popBack() + e = d.last.back() + d.size-- + if d.size == 0 { + //全部删除完成,释放空间,并将首尾节点设为nil + d.first = nil + d.last = nil + } + d.mutex.Unlock() + return e +} + +//@title Front +//@description +// 以deque双向队列容器做接收者 +// 返回该容器的第一个元素,利用首节点进行寻找 +// 若该容器当前为空,则返回nil +//@receiver d *Deque 接收者的deque指针 +//@param nil +//@return e interface{} 容器的第一个元素 +func (d *Deque) Front() (e interface{}) { + if d == nil { + d = New() + } + return d.first.front() +} + +//@title Back +//@description +// 以deque双向队列容器做接收者 +// 返回该容器的最后一个元素,利用尾节点进行寻找 +// 若该容器当前为空,则返回nil +//@receiver d *Deque 接收者的deque指针 +//@param nil +//@return e interface{} 容器的最后一个元素 +func (d *Deque) Back() (e interface{}) { + if d == nil { + d = New() + } + return d.last.back() +} diff --git a/data_structure/deque/deque_test.go b/data_structure/deque/deque_test.go new file mode 100644 index 0000000..2a90eca --- /dev/null +++ b/data_structure/deque/deque_test.go @@ -0,0 +1,36 @@ +package deque + +import ( + "reflect" + "sync" + "testing" +) + +func TestDeque_Front(t *testing.T) { + type fields struct { + first *node + last *node + size uint64 + mutex sync.Mutex + } + tests := []struct { + name string + fields fields + wantE interface{} + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + d := &Deque{ + first: tt.fields.first, + last: tt.fields.last, + size: tt.fields.size, + mutex: tt.fields.mutex, + } + if gotE := d.Front(); !reflect.DeepEqual(gotE, tt.wantE) { + t.Errorf("Front() = %v, want %v", gotE, tt.wantE) + } + }) + } +} diff --git a/data_structure/deque/node.go b/data_structure/deque/node.go new file mode 100644 index 0000000..2d3f28a --- /dev/null +++ b/data_structure/deque/node.go @@ -0,0 +1,263 @@ +package deque + +//@Title deque +//@Description +// deque双队列容器包 +// 该部分包含了deque双向队列中链表节点 +// 链表的增删都通过节点的增删完成 +// 节点空间全部使用或全部废弃后将进行节点增删 +// 增删之后会返回对应的首尾节点以辅助deque容器仍持有首尾节点 +// 为保证效率问题,设定了一定的冗余量,即每个节点设定2^10的空间以存放元素 + +//deque双向队列中链表的node节点结构体 +//包含一个2^10空间的固定数组用以承载元素 +//使用begin和end两个下标用以表示新增的元素的下标,由于begin可能出现-1所以不选用uint16 +//pre和next是该节点的前后两个节点 +//用以保证链表整体是相连的 +type node struct { + data [1024]interface{} //用于承载元素的股东数组 + begin int16 //该结点在前方添加结点的下标 + end int16 //该结点在后方添加结点的下标 + pre *node //该结点的前一个结点 + next *node //该节点的后一个结点 +} + +//deque双向队列容器接口 +//存放了node结点容器可使用的函数 +//对应函数介绍见下方 +type noder interface { + nextNode() (m *node) //返回下一个结点 + preNode() (m *node) //返回上一个结点 + value() (es []interface{}) //返回该结点所承载的所有元素 + pushFront(e interface{}) (first *node) //在该结点头部添加一个元素,并返回新首结点 + pushBack(e interface{}) (last *node) //在该结点尾部添加一个元素,并返回新尾结点 + popFront() (first *node) //弹出首元素并返回首结点 + popBack() (last *node) //弹出尾元素并返回尾结点 + front() (e interface{}) //返回首元素 + back() (e interface{}) //返回尾元素 +} + +//@title createFirst +//@description +// 新建一个冗余在前方的首结点并返回其指针 +// 初始首结点的begin为1023,end为1024 +// 该结点的前后结点均置为nil +//@receiver nil +//@param nil +//@return n *node 新建的node指针 +func createFirst() (n *node) { + return &node{ + data: [1024]interface{}{}, + begin: 1023, + end: 1024, + pre: nil, + next: nil, + } +} + +//@title createLast +//@description +// 新建一个冗余在后方的尾结点并返回其指针 +// 初始首结点的begin为-1,end为0 +// 该结点的前后结点均置为nil +//@receiver nil +//@param nil +//@return n *node 新建的node指针 +func createLast() (n *node) { + return &node{ + data: [1024]interface{}{}, + begin: -1, + end: 0, + pre: nil, + next: nil, + } +} + +//@title nextNode +//@description +// 以node结点做接收者 +// 返回该结点的后一个结点 +// 如果n为nil则返回nil +//@receiver n *node 接收者的node指针 +//@param nil +//@return m *node n结点的下一个结点m的指针 +func (n *node) nextNode() (m *node) { + if n == nil { + return nil + } + return n.next +} + +//@title preNode +//@description +// 以node结点做接收者 +// 返回该结点的前一个结点 +// 如果n为nil则返回nil +//@receiver n *node 接收者的node指针 +//@param nil +//@return m *node n结点的上一个结点m的指针 +func (n *node) preNode() (m *node) { + if n == nil { + return nil + } + return n.pre +} + +//@title value +//@description +// 以node结点做接收者 +// 返回该结点所承载的所有元素 +// 根据其begin和end来获取其元素 +// 当该结点为nil时返回[]而非nil +//@receiver n *node 接收者的node指针 +//@param nil +//@return es []interface{} 该结点所承载的所有元素 +func (n *node) value() (es []interface{}) { + es = make([]interface{}, 0, 0) + if n == nil { + return es + } + if n.begin > n.end { + return es + } + es = n.data[n.begin+1 : n.end] + return es +} + +//@title pushFront +//@description +// 以node结点做接收者 +// 向该节点前方添加元素e +// 当该结点空间已经使用完毕后,新建一个结点并将新结点设为首结点 +// 将插入元素放入新结点并返回新结点作为新的首结点 +// 否则插入当前结点并返回当前结点,首结点不变 +//@receiver n *node 接收者的node指针 +//@param e interface{} 待插入元素 +//@return first *node 首节点指针 +func (n *node) pushFront(e interface{}) (first *node) { + if n == nil { + return n + } + if n.begin >= 0 { + //该结点仍有空间可用于承载元素 + n.data[n.begin] = e + n.begin-- + return n + } + //该结点无空间承载,创建新的首结点用于存放 + m := createFirst() + m.data[m.begin] = e + m.next = n + n.pre = m + m.begin-- + return m +} + +//@title pushBack +//@description +// 以node结点做接收者 +// 向该节点后方添加元素e +// 当该结点空间已经使用完毕后,新建一个结点并将新结点设为尾结点 +// 将插入元素放入新结点并返回新结点作为新的尾结点 +// 否则插入当前结点并返回当前结点,尾结点不变 +//@receiver n *node 接收者的node指针 +//@param e interface{} 待插入元素 +//@return last *node 尾节点指针 +func (n *node) pushBack(e interface{}) (last *node) { + if n == nil { + return n + } + if n.end < int16(len(n.data)) { + //该结点仍有空间可用于承载元素 + n.data[n.end] = e + n.end++ + return n + } + //该结点无空间承载,创建新的尾结点用于存放 + m := createLast() + m.data[m.end] = e + m.pre = n + n.next = m + m.end++ + return m +} + +//@title popFront +//@description +// 以node结点做接收者 +// 利用首节点进行弹出元素,可能存在首节点全部释放要进行首节点后移的情况 +// 当发生首结点后移后将会返回新首结点,否则返回当前结点 +//@receiver n *node 接收者的node指针 +//@param nil +//@return first *node 首节点指针 +func (n *node) popFront() (first *node) { + if n == nil { + return nil + } + if n.begin < int16(len(n.data))-2 { + //该结点仍有承载元素 + n.begin++ + n.data[n.begin] = nil + return n + } + if n.next != nil { + //清除该结点下一节点的前结点指针 + n.next.pre = nil + } + return n.next +} + +//@title popBack +//@description +// 以node结点做接收者 +// 利用尾节点进行弹出元素,可能存在尾节点全部释放要进行尾节点前移的情况 +// 当发生尾结点前移后将会返回新尾结点,否则返回当前结点 +//@receiver n *node 接收者的node指针 +//@param nil +//@return last *node 尾节点指针 +func (n *node) popBack() (last *node) { + if n == nil { + return nil + } + if n.end > 1 { + //该结点仍有承载元素 + n.end-- + n.data[n.end] = nil + return n + } + if n.pre != nil { + //清除该结点上一节点的后结点指针 + n.pre.next = nil + } + return n.pre +} + +//@title front +//@description +// 以node结点做接收者 +// 返回该结点的第一个元素,利用首节点和begin进行查找 +// 若该结点为nil,则返回nil +//@receiver n *node 接收者的node指针 +//@param nil +//@return e interface{} 该结点承载的的第一个元素 +func (n *node) front() (e interface{}) { + if n == nil { + return nil + } + return n.data[n.begin+1] +} + +//@title back +//@description +// 以node结点做接收者 +// 返回该结点的最后一个元素,利用尾节点和end进行查找 +// 若该结点为nil,则返回nil +//@receiver n *node 接收者的node指针 +//@param nil +//@return e interface{} 该结点承载的的最后一个元素 +func (n *node) back() (e interface{}) { + if n == nil { + return nil + } + return n.data[n.end-1] +} diff --git a/data_structure/hashMap/hashMap.go b/data_structure/hashMap/hashMap.go new file mode 100644 index 0000000..f7c1bfe --- /dev/null +++ b/data_structure/hashMap/hashMap.go @@ -0,0 +1,428 @@ +package hashMap + +//@Title hashMap +//@Description +// 哈希映射-hash map +// 分为两层,第一层以vector实现,当出现hash冲突时以avl树存储即第二层 +// 若为基本数据类型可不用传入hash函数,否则需要传入自定义hash函数 +// 所有key不可重复,但value可重复,key不应为nil +// 扩容因子为0.75,当存储数超过0.75倍总容量时应当扩容 +// 使用互斥锁实现并发控制 +import ( + "github.com/hlccd/goSTL/algorithm" + "github.com/hlccd/goSTL/data_structure/avlTree" + "github.com/hlccd/goSTL/data_structure/vector" + "github.com/hlccd/goSTL/utils/comparator" + "github.com/hlccd/goSTL/utils/iterator" + "sync" +) + +//hashMap哈希映射结构体 +//该实例存储第一层vector的指针 +//同时保存hash函数 +//哈希映射中的hash函数在创建时传入,若不传入则在插入首个key-value时从默认hash函数中寻找 +type hashMap struct { + arr *vector.Vector //第一层的vector + hash algorithm.Hasher //hash函数 + size uint64 //当前存储数量 + cap uint64 //vector的容量 + mutex sync.Mutex //并发控制锁 +} + +//索引结构体 +//存储key-value结构 +type indexes struct { + key interface{} + value interface{} +} + +//hashMap哈希映射容器接口 +//存放了hashMap哈希映射可使用的函数 +//对应函数介绍见下方 +type hashMaper interface { + Iterator() (i *Iterator.Iterator) //返回一个包含hashMap容器中所有value的迭代器 + Size() (num uint64) //返回hashMap已存储的元素数量 + Cap() (num uint64) //返回hashMap中的存放空间的容量 + Clear() //清空hashMap + Empty() (b bool) //返回hashMap是否为空 + Insert(key, value interface{}) (b bool) //向hashMap插入以key为索引的value,若存在会覆盖 + Erase(key interface{}) (b bool) //删除hashMap中以key为索引的value + GetKeys() (keys []interface{}) //返回hashMap中所有的keys + Get(key interface{}) (value interface{}) //以key为索引寻找vlue +} + +//@title New +//@description +// 新建一个hashMap哈希映射容器并返回 +// 初始vector长度为16 +// 若有传入的hash函数,则将传入的第一个hash函数设为该hash映射的hash函数 +//@receiver nil +//@param Cmp ...algorithm.Hasher hashMap的hash函数集 +//@return hm *hashMap 新建的hashMap指针 +func New(hash ...algorithm.Hasher) (hm *hashMap) { + var h algorithm.Hasher + if len(hash) == 0 { + h = nil + } else { + h = hash[0] + } + cmp := func(a, b interface{}) int { + ka, kb := a.(*indexes), b.(*indexes) + return comparator.GetCmp(ka.key)(ka.key, kb.key) + } + //新建vector并将其扩容到16 + v := vector.New() + for i := 0; i < 16; i++ { + //vector中嵌套avl树 + v.PushBack(avlTree.New(false, cmp)) + } + return &hashMap{ + arr: v, + hash: h, + size: 0, + cap: 16, + mutex: sync.Mutex{}, + } +} + +//@title Iterator +//@description +// 以hashMap哈希映射做接收者 +// 将该hashMap中所有保存的索引指针的value放入迭代器中 +//@receiver hm *hashMap 接受者hashMap的指针 +//@param nil +//@return i *iterator.Iterator 新建的Iterator迭代器指针 +func (hm *hashMap) Iterator() (i *Iterator.Iterator) { + if hm == nil { + return nil + } + if hm.arr == nil { + return nil + } + hm.mutex.Lock() + //取出hashMap中存放的所有value + values := make([]interface{}, 0, 1) + for i := uint64(0); i < hm.arr.Size(); i++ { + avl := hm.arr.At(i).(*avlTree.AvlTree) + ite := avl.Iterator() + es := make([]interface{}, 0, 1) + for j := ite.Begin(); j.HasNext(); j.Next() { + idx := j.Value().(*indexes) + es = append(es, idx.value) + } + values = append(values, es...) + } + //将所有value放入迭代器中 + i = Iterator.New(&values) + hm.mutex.Unlock() + return i +} + +//@title Size +//@description +// 以hashMap哈希映射做接收者 +// 返回该容器当前含有元素的数量 +// 如果容器为nil返回0 +//@receiver hm *hashMap 接受者hashMap的指针 +//@param nil +//@return num uint64 当前存储的元素数量 +func (hm *hashMap) Size() (num uint64) { + if hm == nil { + return 0 + } + return hm.size +} + +//@title Cap +//@description +// 以hashMap哈希映射做接收者 +// 返回该容器当前容量 +// 如果容器为nil返回0 +//@receiver hm *hashMap 接受者hashMap的指针 +//@param nil +//@return num int 容器中实际占用的容量大小 +func (hm *hashMap) Cap() (num uint64) { + if hm == nil { + return 0 + } + return hm.cap +} + +//@title Clear +//@description +// 以hashMap哈希映射做接收者 +// 将该容器中所承载的元素清空 +// 将该容器的size置0,容量置为16,vector重建并扩容到16 +//@receiver hm *hashMap 接受者hashMap的指针 +//@param nil +//@return nil +func (hm *hashMap) Clear() { + if hm == nil { + return + } + hm.mutex.Lock() + //重建vector并扩容到16 + v := vector.New() + cmp := func(a, b interface{}) int { + ka, kb := a.(*indexes), b.(*indexes) + return comparator.GetCmp(ka.key)(ka.key, kb.key) + } + for i := 0; i < 16; i++ { + v.PushBack(avlTree.New(false, cmp)) + } + hm.arr = v + hm.size = 0 + hm.cap = 16 + hm.mutex.Unlock() +} + +//@title Empty +//@description +// 以hashMap哈希映射做接收者 +// 判断该哈希映射中是否含有元素 +// 如果含有元素则不为空,返回false +// 如果不含有元素则说明为空,返回true +// 如果容器不存在,返回true +//@receiver hm *hashMap 接受者hashMap的指针 +//@param nil +//@return b bool 该容器是空的吗? +func (hm *hashMap) Empty() (b bool) { + if hm == nil { + return false + } + return hm.size > 0 +} + +//@title Insert +//@description +// 以hashMap哈希映射做接收者 +// 向哈希映射入元素e,若已存在相同key则进行覆盖,覆盖仍然视为插入成功 +// 若不存在相同key则直接插入即可 +//@receiver hm *hashMap 接受者hashMap的指针 +//@param key interface{} 待插入元素的key +//@param value interface{} 待插入元素的value +//@return b bool 添加成功? +func (hm *hashMap) Insert(key, value interface{}) (b bool) { + if hm == nil { + return false + } + if hm.arr == nil { + return false + } + if hm.hash == nil { + hm.hash = algorithm.GetHash(key) + } + if hm.hash == nil { + return false + } + hm.mutex.Lock() + //计算hash值并找到对应的avl树 + hash := hm.hash(key) % hm.cap + avl := hm.arr.At(hash).(*avlTree.AvlTree) + idx := &indexes{ + key: key, + value: value, + } + //判断是否存在该avl树中 + if avl.Count(idx) == 0 { + //avl树中不存在相同key,插入即可 + avl.Insert(idx) + hm.size++ + if hm.size >= hm.cap/4*3 { + //当达到扩容条件时候进行扩容 + hm.expend() + } + } else { + //覆盖 + avl.Insert(idx) + } + hm.mutex.Unlock() + return true +} + +//@title expend +//@description +// 以hashMap哈希映射做接收者 +// 对原vector进行扩容 +// 将所有的key-value取出,让vector自行扩容并清空原有结点 +// 扩容后将所有的key-value重新插入vector中 +//@receiver hm *hashMap 接受者hashMap的指针 +//@param nil +//@return nil +func (hm *hashMap) expend() { + //取出所有的key-value + idxs := make([]*indexes, 0, hm.size) + for i := uint64(0); i < hm.arr.Size(); i++ { + avl := hm.arr.At(i).(*avlTree.AvlTree) + ite := avl.Iterator() + for j := ite.Begin(); j.HasNext(); j.Next() { + idxs = append(idxs, j.Value().(*indexes)) + } + } + cmp := func(a, b interface{}) int { + ka, kb := a.(*indexes), b.(*indexes) + return comparator.GetCmp(ka.key)(ka.key, kb.key) + } + //对vector进行扩容,扩容到其容量上限即可 + hm.arr.PushBack(avlTree.New(false, cmp)) + for i := uint64(0); i < hm.arr.Size()-1; i++ { + hm.arr.At(i).(*avlTree.AvlTree).Clear() + } + for i := hm.arr.Size(); i < hm.arr.Cap(); i++ { + hm.arr.PushBack(avlTree.New(false, cmp)) + } + //将vector容量设为hashMap容量 + hm.cap = hm.arr.Cap() + //重新将所有的key-value插入到hashMap中去 + for i := 0; i < len(idxs); i++ { + key, value := idxs[i].key, idxs[i].value + hash := hm.hash(key) % hm.cap + avl := hm.arr.At(hash).(*avlTree.AvlTree) + idx := &indexes{ + key: key, + value: value, + } + avl.Insert(idx) + } +} + +//@title Erase +//@description +// 以hashMap哈希映射做接收者 +// 从hashMap中删除以key为索引的value +// 若存在则删除,否则直接结束,删除成功后size-1 +// 删除后可能出现size<0.75/2*cap且大于16,此时要缩容 +//@receiver hm *hashMap 接受者hashMap的指针 +//@param key interface{} 待删除元素的key +//@return b bool 删除成功? +func (hm *hashMap) Erase(key interface{}) (b bool) { + if hm == nil { + return false + } + if hm.arr == nil { + return false + } + if hm.hash == nil { + return false + } + hm.mutex.Lock() + //计算该key的hash值 + hash := hm.hash(key) % hm.cap + avl := hm.arr.At(hash).(*avlTree.AvlTree) + idx := &indexes{ + key: key, + value: nil, + } + //从对应的avl树中删除该key-value + b = avl.Erase(idx) + if b { + //删除成功,此时size-1,同时进行缩容判断 + hm.size-- + if hm.size < hm.cap/8*3 && hm.cap > 16 { + hm.shrink() + } + } + hm.mutex.Unlock() + return b +} + +//@title shrink +//@description +// 以hashMap哈希映射做接收者 +// 对原vector进行缩容 +// 将所有的key-value取出,让vector自行缩容并清空所有结点 +// 当vector容量与缩容开始时不同时则视为缩容结束 +// 随容后将所有的key-value重新插入vector中 +//@receiver hm *hashMap 接受者hashMap的指针 +//@param nil +//@return nil +func (hm *hashMap) shrink() { + //取出所有key-value + idxs := make([]*indexes, 0, hm.size) + for i := uint64(0); i < hm.arr.Size(); i++ { + avl := hm.arr.At(i).(*avlTree.AvlTree) + ite := avl.Iterator() + for j := ite.Begin(); j.HasNext(); j.Next() { + idxs = append(idxs, j.Value().(*indexes)) + } + } + //进行缩容,当vector的cap与初始不同时,说明缩容结束 + cap := hm.arr.Cap() + for ; cap == hm.arr.Cap(); { + hm.arr.PopBack() + } + hm.cap = hm.arr.Cap() + //将所有的key-value重新放入hashMap中 + for i := 0; i < len(idxs); i++ { + key, value := idxs[i].key, idxs[i].value + hash := hm.hash(key) % hm.cap + avl := hm.arr.At(hash).(*avlTree.AvlTree) + idx := &indexes{ + key: key, + value: value, + } + avl.Insert(idx) + } +} + +//@title GetKeys +//@description +// 以hashMap哈希映射做接收者 +// 返回该hashMap中所有的key +//@receiver hm *hashMap 接受者hashMap的指针 +//@param nil +//@return keys []interface{} hashMap中的所有key +func (hm *hashMap) GetKeys() (keys []interface{}) { + if hm == nil { + return nil + } + if hm.arr == nil { + return nil + } + hm.mutex.Lock() + keys = make([]interface{}, 0, 1) + for i := uint64(0); i < hm.arr.Size(); i++ { + avl := hm.arr.At(i).(*avlTree.AvlTree) + ite := avl.Iterator() + es := make([]interface{}, 0, 1) + for j := ite.Begin(); j.HasNext(); j.Next() { + idx := j.Value().(*indexes) + es = append(es, idx.key) + } + keys = append(keys, es...) + } + hm.mutex.Unlock() + return keys +} + +//@title Get +//@description +// 以hashMap哈希映射做接收者 +// 以key寻找到对应的value并返回 +//@receiver hm *hashMap 接受者hashMap的指针 +//@param keys interface{} 待查找元素的key +//@return keys interface{} 待查找元素的value +func (hm *hashMap) Get(key interface{}) (value interface{}) { + if hm == nil { + return + } + if hm.arr == nil { + return + } + if hm.hash == nil { + hm.hash = algorithm.GetHash(key) + } + if hm.hash == nil { + return + } + hm.mutex.Lock() + //计算hash值 + hash := hm.hash(key) % hm.cap + //从avl树中找到对应该hash值的key-value + info := hm.arr.At(hash).(*avlTree.AvlTree).Find(&indexes{key: key, value: nil}) + hm.mutex.Unlock() + if info == nil { + return nil + } + return info.(*indexes).value +} diff --git a/data_structure/heap/heap.go b/data_structure/heap/heap.go new file mode 100644 index 0000000..12623dd --- /dev/null +++ b/data_structure/heap/heap.go @@ -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 +} diff --git a/data_structure/heap/node.go b/data_structure/heap/node.go new file mode 100644 index 0000000..c27a4d0 --- /dev/null +++ b/data_structure/heap/node.go @@ -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 + } +} \ No newline at end of file diff --git a/data_structure/list/list.go b/data_structure/list/list.go new file mode 100644 index 0000000..c302a16 --- /dev/null +++ b/data_structure/list/list.go @@ -0,0 +1,410 @@ +package list + +//@Title list +//@Description +// list链表容器包 +// 链表将所有结点通过指针的方式串联起来,从而使得其整体保持一个线性状态 +// 对于链表的实现,其增删元素的过程只需要新建一个结点然后插入链表中即可 +// 增删结点需要同步修改其相邻的元素的前后指针以保证其整体是联通的 +// 可接纳不同类型的元素 +// 通过并发控制锁保证了在高并发过程中的数据一致性 + +import ( + "github.com/hlccd/goSTL/utils/comparator" + "github.com/hlccd/goSTL/utils/iterator" + "sync" +) + +//list链表结构体 +//包含链表的头尾节点指针 +//当增删结点时只需要找到对应位置进行操作即可 +//当一个节点进行增删时需要同步修改其临接结点的前后指针 +//结构体中记录整个链表的首尾指针,同时记录其当前已承载的元素 +//使用并发控制锁以保证数据一致性 +type List struct { + first *node //链表首节点指针 + last *node //链表尾节点指针 + size uint64 //当前存储的元素个数 + mutex sync.Mutex //并发控制锁 +} + +//list链表容器接口 +//存放了list容器可使用的函数 +//对应函数介绍见下方 + +type lister interface { + Iterator() (i *Iterator.Iterator) //创建一个包含链表中所有元素的迭代器并返回其指针 + Sort(Cmp ...comparator.Comparator) //将链表中所承载的所有元素进行排序 + Size() (size uint64) //返回链表所承载的元素个数 + Clear() //清空该链表 + Empty() (b bool) //判断该链表是否位空 + Insert(idx uint64, e interface{}) //向链表的idx位(下标从0开始)插入元素组e + Erase(idx uint64) //删除第idx位的元素(下标从0开始) + Get(idx uint64) (e interface{}) //获得下标为idx的元素 + Set(idx uint64, e interface{}) //在下标为idx的位置上放置元素e + IndexOf(e interface{}, Equ ...comparator.Equaler) (idx uint64) //返回和元素e相同的第一个下标 + SubList(begin, num uint64) (newList *List) //从begin开始复制最多num个元素以形成新的链表 +} + +//@title New +//@description +// 新建一个list链表容器并返回 +// 初始链表首尾节点为nil +// 初始size为0 +//@receiver nil +//@param nil +//@return l *List 新建的list指针 +func New() (l *List) { + return &List{ + first: nil, + last: nil, + size: 0, + mutex: sync.Mutex{}, + } +} + +//@title Iterator +//@description +// 以list链表容器做接收者 +// 将list链表容器中所承载的元素放入迭代器中 +//@receiver l *List 接收者的list指针 +//@param nil +//@return i *iterator.Iterator 新建的Iterator迭代器指针 +func (l *List) Iterator() (i *Iterator.Iterator) { + if l == nil { + l = New() + } + l.mutex.Lock() + //将所有元素复制出来放入迭代器中 + tmp := make([]interface{}, l.size, l.size) + for n, idx := l.first, uint64(0); n != nil && idx < l.size; n, idx = n.nextNode(), idx+1 { + tmp[idx] = n.value() + } + i = Iterator.New(&tmp) + l.mutex.Unlock() + return i +} + +//@title Sort +//@description +// 以list链表容器做接收者 +// 将list链表容器中所承载的元素利用比较器进行排序 +// 可以自行传入比较函数,否则将调用默认比较函数 +//@receiver l *List 接收者的list指针 +//@param Cmp ...comparator.Comparator 比较函数 +//@return nil +func (l *List) Sort(Cmp ...comparator.Comparator) { + if l == nil { + l = New() + } + l.mutex.Lock() + //将所有元素复制出来用于排序 + tmp := make([]interface{}, l.size, l.size) + for n, idx := l.first, uint64(0); n != nil && idx < l.size; n, idx = n.nextNode(), idx+1 { + tmp[idx] = n.value() + } + if len(Cmp) > 0 { + comparator.Sort(&tmp, Cmp[0]) + } else { + comparator.Sort(&tmp) + } + //将排序结果再放入链表中 + for n, idx := l.first, uint64(0); n != nil && idx < l.size; n, idx = n.nextNode(), idx+1 { + n.setValue(tmp[idx]) + } + l.mutex.Unlock() +} + +//@title Size +//@description +// 以list链表容器做接收者 +// 返回该容器当前含有元素的数量 +//@receiver l *List 接收者的list指针 +//@param nil +//@return num int 容器中所承载的元素数量 +func (l *List) Size() (size uint64) { + if l == nil { + l = New() + } + return l.size +} + +//@title Clear +//@description +// 以list链表容器做接收者 +// 将该容器中所承载的元素清空 +// 将该容器的首尾指针均置nil,将size重置为0 +//@receiver l *List 接收者的list指针 +//@param nil +//@return nil +func (l *List) Clear() { + if l == nil { + l = New() + } + l.mutex.Lock() + //销毁链表 + l.first = nil + l.last = nil + l.size = 0 + l.mutex.Unlock() +} + +//@title Empty +//@description +// 以list链表容器做接收者 +// 判断该list链表容器是否含有元素 +// 如果含有元素则不为空,返回false +// 如果不含有元素则说明为空,返回true +// 如果容器不存在,返回true +// 该判断过程通过size进行判断,为0则为true,否则为false +//@receiver l *List 接收者的list指针 +//@param nil +//@return b bool 该容器是空的吗? +func (l *List) Empty() (b bool) { + if l == nil { + l = New() + } + return l.size == 0 +} + +//@title Insert +//@description +// 以list链表容器做接收者 +// 通过链表的首尾结点进行元素插入 +// 插入的元素可以有很多个 +// 通过判断idx +//@receiver l *List 接收者的list指针 +//@param e interface{} 待插入元素 +//@return nil +func (l *List) Insert(idx uint64, e interface{}) { + if l == nil { + l = New() + } + l.mutex.Lock() + n := newNode(e) + if l.size == 0 { + //链表中原本无元素,新建链表 + l.first = n + l.last = n + } else { + //链表中存在元素 + if idx == 0 { + //插入头节点 + n.insertNext(l.first) + l.first = n + } else if idx >= l.size { + //插入尾节点 + l.last.insertNext(n) + l.last = n + } else { + //插入中间节点 + //根据插入的位置选择从前或从后寻找 + if idx < l.size/2 { + //从首节点开始遍历寻找 + m := l.first + for i := uint64(0); i < idx-1; i++ { + m = m.nextNode() + } + m.insertNext(n) + } else { + //从尾节点开始遍历寻找 + m := l.last + for i := l.size - 1; i > idx; i-- { + m = m.preNode() + } + m.insertPre(n) + } + } + } + l.size++ + l.mutex.Unlock() +} + +//@title Erase +//@description +// 以list链表容器做接收者 +// 先判断是否为首尾结点,如果是首尾结点,在删除后将设置新的首尾结点 +// 当链表所承载的元素全部删除后则销毁链表 +// 删除时通过idx与总元素数量选择从前或从后进行遍历以找到对应位置 +// 删除后,将该位置的前后结点连接起来,以保证链表不断裂 +//@receiver l *List 接收者的list指针 +//@param idx uint64 被删除结点的下标(从0开始) +//@return nil +func (l *List) Erase(idx uint64) { + if l == nil { + l = New() + } + l.mutex.Lock() + if l.size > 0 && idx < l.size { + //链表中存在元素,且要删除的点在范围内 + if idx == 0 { + //删除头节点 + l.first = l.first.next + } else if idx == l.size-1 { + //删除尾节点 + l.last = l.last.pre + } else { + //删除中间节点 + //根据删除的位置选择从前或从后寻找 + if idx < l.size/2 { + //从首节点开始遍历寻找 + m := l.first + for i := uint64(0); i < idx; i++ { + m = m.nextNode() + } + m.erase() + } else { + //从尾节点开始遍历寻找 + m := l.last + for i := l.size - 1; i > idx; i-- { + m = m.preNode() + } + m.erase() + } + } + l.size-- + if l.size == 0 { + //所有节点都被删除,销毁链表 + l.first = nil + l.last = nil + } + } + l.mutex.Unlock() +} + +//@title Get +//@description +// 以list链表容器做接收者 +// 获取第idx位结点所承载的元素,若不在链表范围内则返回nil +//@receiver l *List 接收者的list指针 +//@param idx uint64 被获取的结点位置(从0开始) +//@return e interface{} 获取的元素 +func (l *List) Get(idx uint64) (e interface{}) { + if l == nil { + l = New() + } + if idx >= l.size { + return nil + } + l.mutex.Lock() + if idx < l.size/2 { + //从首节点开始遍历寻找 + m := l.first + for i := uint64(0); i < idx; i++ { + m = m.nextNode() + } + e = m.value() + } else { + //从尾节点开始遍历寻找 + m := l.last + for i := l.size - 1; i > idx; i-- { + m = m.preNode() + } + e = m.value() + } + l.mutex.Unlock() + return e +} + +//@title Set +//@description +// 以list链表容器做接收者 +// 修改第idx为结点所承载的元素,超出范围则不修改 +//@receiver l *List 接收者的list指针 +//@param idx uint64 被修改的结点位置(从0开始) +//@param e interface{} 修改后当元素 +//@return nil +func (l *List) Set(idx uint64, e interface{}) { + if l == nil { + l = New() + } + if idx >= l.size { + return + } + l.mutex.Lock() + if idx < l.size/2 { + //从首节点开始遍历寻找 + m := l.first + for i := uint64(0); i < idx; i++ { + m = m.nextNode() + } + m.setValue(e) + } else { + //从尾节点开始遍历寻找 + m := l.last + for i := l.size - 1; i > idx; i-- { + m = m.preNode() + } + m.setValue(e) + } + l.mutex.Unlock() +} + +//@title IndexOf +//@description +// 以list链表容器做接收者 +// 返回与e相同的元素的首个位置 +// 可以自行传入用于判断相等的相等器进行处理 +// 遍历从头至尾,如果不存在则返回l.size +//@receiver l *List 接收者的list指针 +//@param e interface{} 要查找的元素 +//@param Equ ...comparator.Equaler 相等器 +//@param idx uint64 首下标 +func (l *List) IndexOf(e interface{}, Equ ...comparator.Equaler) (idx uint64) { + if l == nil { + l = New() + } + l.mutex.Lock() + var equ comparator.Equaler + if len(Equ) > 0 { + equ = Equ[0] + } else { + equ = comparator.GetEqual() + } + n := l.first + //从头寻找直到找到相等的两个元素即可返回 + for idx = 0; idx < l.size && n != nil; idx++ { + if equ(n.value(), e) { + break + } + n = n.nextNode() + } + l.mutex.Unlock() + return idx +} + +//@title SubList +//@description +// 以list链表容器做接收者 +// 以begin为起点(包含),最多复制num个元素进入新链表 +// 并返回新链表指针 +//@receiver l *List 接收者的list指针 +//@param begin uint64 复制起点 +//@param num uint64 复制个数上限 +//@param newList *List 新链表指针 +func (l *List) SubList(begin, num uint64) (newList *List) { + if l == nil { + l = New() + } + newList = New() + l.mutex.Lock() + if begin < l.size { + //起点在范围内,可以复制 + n := l.first + for i := uint64(0); i < begin; i++ { + n = n.nextNode() + } + m := newNode(n.value()) + newList.first = m + newList.size++ + for i := uint64(0); i < num-1 && i+begin < l.size-1; i++ { + n = n.nextNode() + m.insertNext(newNode(n.value())) + m = m.nextNode() + newList.size++ + } + newList.last = m + } + l.mutex.Unlock() + return newList +} diff --git a/data_structure/list/node.go b/data_structure/list/node.go new file mode 100644 index 0000000..05c933d --- /dev/null +++ b/data_structure/list/node.go @@ -0,0 +1,169 @@ +package list + +//@Title list +//@Description +// list链表容器包 +// 该部分包含了链表的节点 +// 链表的增删都通过节点的增删完成 +// 结点间可插入其前后节点,并同时将两结点建立连接 +// 增删之后会返回对应的首尾节点以辅助list容器仍持有首尾节点 +// 为保证效率问题,设定了一定的冗余量,即每个节点设定2^10的空间以存放元素 + +//链表的node节点结构体 +//pre和next是该节点的前后两个节点的指针 +//用以保证链表整体是相连的 +type node struct { + data interface{} //结点所承载的元素 + pre *node //前结点指针 + next *node //后结点指针 +} + +//node结点容器接口 +//存放了node容器可使用的函数 +//对应函数介绍见下方 + +type noder interface { + preNode() (m *node) //返回前结点指针 + nextNode() (m *node) //返回后结点指针 + insertPre(pre *node) //在该结点前插入结点并建立连接 + insertNext(next *node) //在该结点后插入结点并建立连接 + erase() //删除该结点,并使该结点前后两结点建立连接 + value() (e interface{}) //返回该结点所承载的元素 + setValue(e interface{}) //修改该结点承载元素为e +} + +//@title newNode +//@description +// 新建一个结点并返回其指针 +// 初始首结点的前后结点指针都为nil +//@receiver nil +//@param nil +//@return n *node 新建的node指针 +func newNode(e interface{}) (n *node) { + return &node{ + data: e, + pre: nil, + next: nil, + } +} + +//@title preNode +//@description +// 以node结点做接收者 +// 返回该结点的前结点 +//@receiver n *node 接收者的node指针 +//@param nil +//@return pre *node 该结点的前结点指针 +func (n *node) preNode() (pre *node) { + if n == nil { + return + } + return n.pre +} + +//@title nextNode +//@description +// 以node结点做接收者 +// 返回该结点的后结点 +//@receiver n *node 接收者的node指针 +//@param nil +//@return next *node 该结点的后结点指针 +func (n *node) nextNode() (next *node) { + if n == nil { + return + } + return n.next +} + +//@title insertPre +//@description +// 以node结点做接收者 +// 对该结点插入前结点 +// 并建立前结点和该结点之间的连接 +//@receiver n *node 接收者的node指针 +//@param pre *node 该结点的前结点指针 +//@return nil +func (n *node) insertPre(pre *node) { + if n == nil || pre == nil { + return + } + pre.next = n + pre.pre = n.pre + if n.pre != nil { + n.pre.next = pre + } + n.pre = pre +} + +//@title insertNext +//@description +// 以node结点做接收者 +// 对该结点插入后结点 +// 并建立后结点和该结点之间的连接 +//@receiver n *node 接收者的node指针 +//@param next *node 该结点的后结点指针 +//@return nil +func (n *node) insertNext(next *node) { + if n == nil || next == nil { + return + } + next.pre = n + next.next = n.next + if n.next != nil { + n.next.pre = next + } + n.next = next +} + +//@title erase +//@description +// 以node结点做接收者 +// 销毁该结点 +// 同时建立该节点前后节点之间的连接 +//@receiver n *node 接收者的node指针 +//@param nil +//@return nil +func (n *node) erase() { + if n == nil { + return + } + if n.pre == nil && n.next == nil { + return + } else if n.pre == nil { + n.next.pre = nil + } else if n.next == nil { + n.pre.next = nil + } else { + n.pre.next = n.next + n.next.pre = n.pre + } + n = nil +} + +//@title value +//@description +// 以node结点做接收者 +// 返回该结点所要承载的元素 +//@receiver n *node 接收者的node指针 +//@param nil +//@return e interface{} 该节点所承载的元素e +func (n *node) value() (e interface{}) { + if n == nil { + return nil + } + return n.data +} + +//@title setValue +//@description +// 以node结点做接收者 +// 对该结点设置其承载的元素 +//@receiver n *node 接收者的node指针 +//@param e interface{} 该节点所要承载的元素e +//@return nil +func (n *node) setValue(e interface{}) { + if n == nil { + return + } + n.data = e +} diff --git a/data_structure/lru/lru.go b/data_structure/lru/lru.go new file mode 100644 index 0000000..f469b85 --- /dev/null +++ b/data_structure/lru/lru.go @@ -0,0 +1,240 @@ +package lru + +//@Title lru +//@Description +// LRU-Least Recently Used,最近最少使用链结构 +// 相对于仅考虑时间因素的FIFO和仅考虑访问频率的LFU,LRU算法可以认为是相对平衡的一种淘汰算法 +// LRU认为,如果数据最近被访问过,那么将来被访问的概率也会更高 +// LRU 算法的实现非常简单,维护一个队列 +// 如果某条记录被访问了,则移动到队尾,那么队首则是最近最少访问的数据,淘汰该条记录即可。 +// 可接纳不同类型的元素 +// 使用并发控制锁保证线程安全 +// 使用map加快索引速率 +// 不做定时淘汰 +import ( + "container/list" + "sync" +) + +//LRU链结构体 +//包含了该LRU结构中能承载的byte数上限和当前已承载的数量 +//以链表的形式存储承载元素 +//使用map建立key索引和链表结点之间的联系,链表结点中存放其value +//onRemove函数是用于在删除时的执行,可用于将数据持久化 +//使用并发控制所保证线程安全 +type LRU struct { + maxBytes int64 //所能承载的最大byte数量 + nowBytes int64 //当前承载的byte数 + ll *list.List //用于存储的链表 + cache map[string]*list.Element //链表元素与key的映射表 + onRemove func(key string, value Value) //删除元素时的执行函数 + mutex sync.Mutex //并发控制锁 +} + +//索引结构体 +//保存了一个待存储值的索引和值 +//value值为一个interface{},需要实现它的长度函数即Len() +type indexes struct { + key string //索引 + value Value //存储值 +} + +//存储值的函数 +type Value interface { + Len() int //用于计算该存储值所占用的长度 +} + +//lru链容器接口 +//存放了lru容器可使用的函数 +//对应函数介绍见下方 +type lruer interface { + Size() (num int64) //返回lru中当前存放的byte数 + Cap() (num int64) //返回lru能存放的byte树的最大值 + Clear() //清空lru,将其中存储的所有元素都释放 + Empty() (b bool) //判断该lru中是否存储了元素 + Insert(key string, value Value) //向lru中插入以key为索引的value + Erase(key string) //从lru中删除以key为索引的值 + Get(key string) (value Value, ok bool) //从lru中获取以key为索引的value和是否获取成功? +} + +//@title New +//@description +// 新建一个lru链容器并返回 +// 初始的lru不存储元素 +// 需要传入其最大存储的bytes和删除后的执行函数 +//@receiver nil +//@param maxBytes int64 该LRU能存储的最大byte数 +//@param onRemove func(string, Value) 删除元素后的执行函数,一般建议做持久化 +//@return l *LRU 新建的LRU指针 +func New(maxBytes int64, onRemove func(string, Value)) (l *LRU) { + return &LRU{ + maxBytes: maxBytes, + nowBytes: 0, + ll: list.New(), + cache: make(map[string]*list.Element), + onRemove: onRemove, + mutex: sync.Mutex{}, + } +} + +//@title Size +//@description +// 以LRU链容器做接收者 +// 返回该LRU链当前所存储的byte数 +//@receiver l *LRU 接受者LRU的指针 +//@param nil +//@return num uint64 该LRU链当前所存储的byte数 +func (l *LRU) Size() (num int64) { + if l == nil { + return 0 + } + return l.nowBytes +} + +//@title Cap +//@description +// 以LRU链容器做接收者 +// 返回该LRU链能存储的最大byte数 +//@receiver l *LRU 接受者LRU的指针 +//@param nil +//@return num uint64 该LRU链所能存储的最大byte数 +func (l *LRU) Cap() (num int64) { + if l == nil { + return 0 + } + return l.maxBytes +} + +//@title Clear +//@description +// 以LRU链容器做接收者 +// 将LRU链中的所有承载的元素清除 +// 同时将map清空,将当前存储的byte数清零 +//@receiver l *LRU 接受者LRU的指针 +//@param nil +//@return nil +func (l *LRU) Clear() { + if l == nil { + return + } + l.mutex.Lock() + l.ll = list.New() + l.cache = make(map[string]*list.Element) + l.nowBytes = 0 + l.mutex.Unlock() +} + +//@title Empty +//@description +// 以LRU链容器做接收者 +// 判断该LRU链中是否存储了元素 +// 没存储则返回true,LRU不存在也返回true +// 否则返回false +//@receiver l *LRU 接受者LRU的指针 +//@param nil +//@return b bool 该容器是空的吗? +func (l *LRU) Empty() (b bool) { + if l == nil { + return true + } + return l.nowBytes <= 0 +} + +//@title Insert +//@description +// 以LRU链容器做接收者 +// 向该LRU中插入以key为索引的value +// 若已经存在则将其放到队尾 +// 若空间充足且不存在则直接插入队尾 +// 若空间不足则淘汰队首元素再将其插入队尾 +// 插入完成后将当前已存的byte数增加 +//@receiver l *LRU 接受者LRU的指针 +//@param key string 待插入结点的索引key +//@param value Value 待插入元素的值value,本质也是个interface{} +//@return nil +func (l *LRU) Insert(key string, value Value) { + l.mutex.Lock() + //利用map从已存的元素中寻找 + if ele, ok := l.cache[key]; ok { + //该key已存在,直接替换即可 + l.ll.MoveToFront(ele) + kv := ele.Value.(*indexes) + //此处是一个替换,即将cache中的value替换为新的value,同时根据实际存储量修改其当前存储的实际大小 + l.nowBytes += int64(value.Len()) - int64(kv.value.Len()) + kv.value = value + } else { + //该key不存在,需要进行插入 + ele := l.ll.PushFront(&indexes{key, value}) + l.cache[key] = ele + //此处是一个增加操作,即原本不存在,所以直接插入即可,同时在当前数值范围内增加对应的占用空间 + l.nowBytes += int64(len(key)) + int64(value.Len()) + } + //添加完成后根据删除掉尾部一部分数据以保证实际使用空间小于设定的空间上限 + for l.maxBytes != 0 && l.maxBytes < l.nowBytes { + //删除队尾元素 + //删除后执行创建时传入的删除执行函数 + ele := l.ll.Back() + if ele != nil { + l.ll.Remove(ele) + kv := ele.Value.(*indexes) + //删除最末尾的同时将其占用空间减去 + delete(l.cache, kv.key) + l.nowBytes -= int64(len(kv.key)) + int64(kv.value.Len()) + if l.onRemove != nil { + //删除后的回调函数,可用于持久化该部分数据 + l.onRemove(kv.key, kv.value) + } + } + } + l.mutex.Unlock() +} + +//@title Erase +//@description +// 以LRU链容器做接收者 +// 从LRU链中删除以key为索引的value +// 如果不存在则直接结束 +// 删除完成后将其占用的byte数减去 +// 删除后执行函数回调函数,一般用于持久化 +//@receiver l *LRU 接受者LRU的指针 +//@param key string 待删除的索引key +//@return nil +//以key为索引删除元素 +func (l *LRU) Erase(key string) { + l.mutex.Lock() + if ele, ok := l.cache[key]; ok { + l.ll.Remove(ele) + kv := ele.Value.(*indexes) + //删除的同时将其占用空间减去 + delete(l.cache, kv.key) + l.nowBytes -= int64(len(kv.key)) + int64(kv.value.Len()) + if l.onRemove != nil { + //删除后的回调函数,可用于持久化该部分数据 + l.onRemove(kv.key, kv.value) + } + } + l.mutex.Unlock() +} + +//@title Get +//@description +// 以LRU链容器做接收者 +// 从LRU链中寻找以key为索引的value +// 找到对应的value后将其移到首部,随后返回其value +// 如果没找到以key为索引的value,直接结束即可 +//@receiver l *LRU 接受者LRU的指针 +//@param key string 待查找的索引key +//@return value Value 以key为索引的value,本质是个interface{} +//@return ok bool 查找成功? +func (l *LRU) Get(key string) (value Value, ok bool) { + l.mutex.Lock() + if ele, ok := l.cache[key]; ok { + //找到了value,将其移到链表首部 + l.ll.MoveToFront(ele) + kv := ele.Value.(*indexes) + l.mutex.Unlock() + return kv.value, true + } + l.mutex.Unlock() + return nil, false +} diff --git a/data_structure/priority_queue/priority_queue.go b/data_structure/priority_queue/priority_queue.go new file mode 100644 index 0000000..3455000 --- /dev/null +++ b/data_structure/priority_queue/priority_queue.go @@ -0,0 +1,281 @@ +package priority_queue + +//@Title priority_queue +//@Description +// priority_queue优先队列集合容器包 +// 以动态数组的形式实现 +// 该容器可以增减元素使最值元素处于顶端 +// 若使用默认比较器,顶端元素是最小元素 +// 该集合只能对于相等元素可以存储多个 +// 可接纳不同类型的元素,但为了便于比较,建议使用同一个类型 +// 使用互斥锁实现并发控制,以保证在高并发情况下的数据一致性 +import ( + "github.com/hlccd/goSTL/utils/comparator" + "sync" +) + +//priority_queue优先队列集合结构体 +//包含动态数组和比较器,同时包含其实际使用长度和实际占用空间容量 +//该数据结构可以存储多个相同的元素,并不会产生冲突 +//增删节点后会使用比较器保持该动态数组的相对有序性 +type Priority_queue struct { + data []interface{} //动态数组 + len uint64 //实际使用长度 + cap uint64 //实际占用的空间的容量 + cmp comparator.Comparator //该优先队列的比较器 + mutex sync.Mutex //并发控制锁 +} + +//priority_queue优先队列容器接口 +//存放了priority_queue容器可使用的函数 +//对应函数介绍见下方 +type priority_queueer interface { + Size() (num uint64) //返回该容器存储的元素数量 + Clear() //清空该容器 + Empty() (b bool) //判断该容器是否为空 + Push(e interface{}) //将元素e插入该容器 + Pop() //弹出顶部元素 + Top() (e interface{}) //返回顶部元素 +} + +//@title New +//@description +// 新建一个priority_queue优先队列容器并返回 +// 初始priority_queue的切片数组为空 +// 如果有传入比较器,则将传入的第一个比较器设为可重复集合默认比较器 +// 如果不传入比较器,在后续的增删过程中将会去寻找默认比较器 +//@receiver nil +//@param Cmp ...comparator.Comparator priority_queue的比较器 +//@return pq *Priority_queue 新建的priority_queue指针 +func New(cmps ...comparator.Comparator) (pq *Priority_queue) { + var cmp comparator.Comparator + if len(cmps) == 0 { + cmp = nil + } else { + cmp = cmps[0] + } + //比较器为nil时后续的增删将会去寻找默认比较器 + return &Priority_queue{ + data: make([]interface{}, 1, 1), + len: 0, + cap: 1, + cmp: cmp, + mutex: sync.Mutex{}, + } +} + +//@title Size +//@description +// 以priority_queue容器做接收者 +// 返回该容器当前含有元素的数量 +//@receiver pq *Priority_queue 接受者priority_queue的指针 +//@param nil +//@return num uint64 容器中存储元素的个数 +func (pq *Priority_queue) Size() (num uint64) { + if pq == nil { + pq = New() + } + return pq.len +} + +//@title Clear +//@description +// 以priority_queue容器做接收者 +// 将该容器中所承载的元素清空 +//@receiver pq *Priority_queue 接受者priority_queue的指针 +//@param nil +//@return nil +func (pq *Priority_queue) Clear() { + if pq == nil { + pq = New() + } + pq.mutex.Lock() + //清空已分配的空间 + pq.data = make([]interface{}, 1, 1) + pq.len = 0 + pq.cap = 1 + pq.mutex.Unlock() +} + +//@title Empty +//@description +// 以priority_queue容器做接收者 +// 判断该priority_queue容器是否含有元素 +// 如果含有元素则不为空,返回false +// 如果不含有元素则说明为空,返回true +// 如果容器不存在,返回true +// 该判断过程通过含有元素个数进行判断 +//@receiver pq *Priority_queue 接受者priority_queue的指针 +//@param nil +//@return b bool 该容器是空的吗? +func (pq *Priority_queue) Empty() bool { + if pq == nil { + pq = New() + } + return pq.len == 0 +} + +//@title Push +//@description +// 以priority_queue容器做接收者 +// 在该优先队列中插入元素e,利用比较器和交换使得优先队列保持相对有序状态 +// 插入时,首先将该元素放入末尾,然后通过比较其逻辑上的父结点选择是否上移 +// 扩容策略同vector,先进行翻倍扩容,在进行固定扩容,界限为2^16 +//@receiver pq *Priority_queue 接受者priority_queue的指针 +//@param e interface{} 待插入元素 +//@return nil +func (pq *Priority_queue) Push(e interface{}) { + if pq == nil { + pq = New() + } + pq.mutex.Lock() + //判断是否存在比较器,不存在则寻找默认比较器,若仍不存在则直接结束 + if pq.cmp == nil { + pq.cmp = comparator.GetCmp(e) + } + if pq.cmp == nil { + pq.mutex.Unlock() + return + } + //先判断是否需要扩容,同时使用和vector相同的扩容策略 + //即先翻倍扩容再固定扩容,随后在末尾插入元素e + if pq.len < pq.cap { + //还有冗余,直接添加 + pq.data[pq.len] = e + } else { + //冗余不足,需要扩容 + if pq.cap <= 65536 { + //容量翻倍 + if pq.cap == 0 { + pq.cap = 1 + } + pq.cap *= 2 + } else { + //容量增加2^16 + pq.cap += 65536 + } + //复制扩容前的元素 + tmp := make([]interface{}, pq.cap, pq.cap) + copy(tmp, pq.data) + pq.data = tmp + pq.data[pq.len] = e + } + pq.len++ + //到此时,元素以插入到末尾处,同时插入位的元素的下标为pq.len-1,随后将对该位置的元素进行上升 + //即通过比较它逻辑上的父结点进行上升 + pq.up(pq.len - 1) + pq.mutex.Unlock() +} + +//@title up +//@description +// 以priority_queue容器做接收者 +// 用于递归判断任意子结点和其父结点之间的关系,满足上升条件则递归上升 +// 从而保证父节点必然都大于或都小于子节点 +//@receiver pq *Priority_queue 接受者priority_queue的指针 +//@param p uint64 待上升节点的位置 +//@return nil +func (pq *Priority_queue) up(p uint64) { + if p == 0 { + //以及上升到顶部,直接结束即可 + return + } + if pq.cmp(pq.data[(p-1)/2], pq.data[p]) > 0 { + //判断该结点和其父结点的关系 + //满足给定的比较函数的关系则先交换该结点和父结点的数值,随后继续上升即可 + pq.data[p], pq.data[(p-1)/2] = pq.data[(p-1)/2], pq.data[p] + pq.up((p - 1) / 2) + } +} + +//@title Pop +//@description +// 以priority_queue容器做接收者 +// 在该优先队列中删除顶部元素,利用比较器和交换使得优先队列保持相对有序状态 +// 删除时首先将首结点移到最后一位进行交换,随后删除最后一位即可,然后对首节点进行下降即可 +// 缩容时同vector一样,先进行固定缩容在进行折半缩容,界限为2^16 +//@receiver pq *Priority_queue 接受者priority_queue的指针 +//@param nil +//@return nil +func (pq *Priority_queue) Pop() { + if pq == nil { + pq = New() + } + if pq.Empty() { + return + } + pq.mutex.Lock() + //将最后一位移到首位,随后删除最后一位,即删除了首位,同时判断是否需要缩容 + pq.data[0] = pq.data[pq.len-1] + pq.data[pq.len-1]=nil + pq.len-- + //缩容判断,缩容策略同vector,即先固定缩容在折半缩容 + if pq.cap-pq.len >= 65536 { + //容量和实际使用差值超过2^16时,容量直接减去2^16 + pq.cap -= 65536 + tmp := make([]interface{}, pq.cap, pq.cap) + copy(tmp, pq.data) + pq.data = tmp + } else if pq.len*2 < pq.cap { + //实际使用长度是容量的一半时,进行折半缩容 + pq.cap /= 2 + tmp := make([]interface{}, pq.cap, pq.cap) + copy(tmp, pq.data) + pq.data = tmp + } + //判断是否为空,为空则直接结束 + if pq.Empty() { + pq.mutex.Unlock() + return + } + //对首位进行下降操作,即对比其逻辑上的左右结点判断是否应该下降,再递归该过程即可 + pq.down(0) + pq.mutex.Unlock() +} + +//@title down +//@description +// 以priority_queue容器做接收者 +// 判断待下沉节点与其左右子节点的大小关系以确定是否进行递归上升 +// 从而保证父节点必然都大于或都小于子节点 +//@receiver pq *Priority_queue 接受者priority_queue的指针 +//@param p uint64 待下沉节点的位置 +//@return nil +func (pq *Priority_queue) down(p uint64) { + q := p + //先判断其左结点是否在范围内,然后在判断左结点是否满足下降条件 + if 2*p+1 <= pq.len-1 && pq.cmp(pq.data[p], pq.data[2*p+1]) > 0 { + q = 2*p + 1 + } + //在判断右结点是否在范围内,同时若判断右节点是否满足下降条件 + if 2*p+2 <= pq.len-1 && pq.cmp(pq.data[q], pq.data[2*p+2]) > 0 { + q = 2*p + 2 + } + //根据上面两次判断,从最小一侧进行下降 + if p != q { + //进行交互,递归下降 + pq.data[p], pq.data[q] = pq.data[q], pq.data[p] + pq.down(q) + } +} + +//@title Top +//@description +// 以priority_queue容器做接收者 +// 返回该优先队列容器的顶部元素 +// 如果容器不存在或容器为空,返回nil +//@receiver pq *Priority_queue 接受者priority_queue的指针 +//@param nil +//@return e interface{} 优先队列顶元素 +func (pq *Priority_queue) Top() (e interface{}) { + if pq == nil { + pq = New() + } + if pq.Empty() { + return nil + } + pq.mutex.Lock() + e = pq.data[0] + pq.mutex.Unlock() + return e +} diff --git a/data_structure/queue/queue.go b/data_structure/queue/queue.go new file mode 100644 index 0000000..5389071 --- /dev/null +++ b/data_structure/queue/queue.go @@ -0,0 +1,267 @@ +package queue + +//@Title queue +//@Description +// queue队列容器包 +// 以动态数组的形式实现 +// 该容器可以在尾部实现线性增加元素,在首部实现线性减少元素 +// 队列的扩容和缩容同vector一样,即数组小采用翻倍扩缩容/折半缩容,数组大时采用固定扩/缩容 +// 该容器满足FIFO的先进先出模式 +// 可接纳不同类型的元素 +// 通过并发控制锁保证了在高并发过程中的数据一致性 + +import ( + "github.com/hlccd/goSTL/utils/iterator" + "sync" +) + +//queue队列结构体 +//包含泛型切片和该切片的首尾位的下标 +//当删除节点时仅仅需要后移首位一位即可 +//当剩余长度较小时采用缩容策略进行缩容以释放空间 +//当添加节点时若未占满全部已分配空间则尾指针后移一位同时进行覆盖存放 +//当添加节点时尾指针大于已分配空间长度,则先去掉首部多出来的空间,如果还不足则进行扩容 +//首节点指针始终不能超过尾节点指针 +type Queue struct { + data []interface{} //泛型切片 + begin uint64 //首节点下标 + end uint64 //尾节点下标 + cap uint64 //容量 + mutex sync.Mutex //并发控制锁 +} + +//queue队列容器接口 +//存放了queue容器可使用的函数 +//对应函数介绍见下方 + +type queuer interface { + Iterator() (i *Iterator.Iterator) //返回包含队列中所有元素的迭代器 + Size() (size uint64) //返回该队列中元素的使用空间大小 + Clear() //清空该队列 + Empty() (b bool) //判断该队列是否为空 + Push(e interface{}) //将元素e添加到该队列末尾 + Pop() (e interface{}) //将该队列首元素弹出并返回 + Front() (e interface{}) //获取该队列首元素 + Back() (e interface{}) //获取该队列尾元素 +} + +//@title New +//@description +// 新建一个queue队列容器并返回 +// 初始queue的切片数组为空 +// 初始queue的首尾指针均置零 +//@receiver nil +//@param nil +//@return q *Queue 新建的queue指针 +func New() (q *Queue) { + return &Queue{ + data: make([]interface{}, 1, 1), + begin: 0, + end: 0, + cap: 1, + mutex: sync.Mutex{}, + } +} + +//@title Iterator +//@description +// 以queue队列容器做接收者 +// 将queue队列容器中不使用空间释放掉 +//@return q *Queue 接收者的queue指针 +//@param nil +//@return i *iterator.Iterator 新建的Iterator迭代器指针 +func (q *Queue) Iterator() (i *Iterator.Iterator) { + if q == nil { + q = New() + } + q.mutex.Lock() + tmp := make([]interface{}, q.end-q.begin, q.end-q.begin) + copy(tmp, q.data[q.begin:q.end]) + i = Iterator.New(&tmp) + q.mutex.Unlock() + return i +} + +//@title Size +//@description +// 以queue队列容器做接收者 +// 返回该容器当前含有元素的数量 +// 该长度并非实际占用空间数量 +// 若容器为空则返回0 +//@receiver q *Queue 接受者queue的指针 +//@param nil +//@return size uint64 容器中实际使用元素所占空间大小 +func (q *Queue) Size() (size uint64) { + if q == nil { + q = New() + } + return q.end - q.begin +} + +//@title Clear +//@description +// 以queue队列容器做接收者 +// 将该容器中所承载的元素清空 +// 将该容器的首尾指针均置0,容量设为1 +//@receiver q *Queue 接受者queue的指针 +//@param nil +//@return nil +func (q *Queue) Clear() { + if q == nil { + q = New() + } + q.mutex.Lock() + q.data = make([]interface{}, 1, 1) + q.begin = 0 + q.end = 0 + q.cap = 1 + q.mutex.Unlock() +} + +//@title Empty +//@description +// 以queue队列容器做接收者 +// 判断该queue队列容器是否含有元素 +// 如果含有元素则不为空,返回false +// 如果不含有元素则说明为空,返回true +// 如果容器不存在,返回true +// 该判断过程通过首尾指针数值进行判断 +// 当尾指针数值等于首指针时说明不含有元素 +// 当尾指针数值大于首指针时说明含有元素 +//@receiver q *Queue 接受者queue的指针 +//@param nil +//@return b bool 该容器是空的吗? +func (q *Queue) Empty() (b bool) { + if q == nil { + q = New() + } + return q.Size() <= 0 +} + +//@title Push +//@description +// 以queue队列向量容器做接收者 +// 在容器尾部插入元素 +// 若尾指针小于切片实际使用长度,则对当前指针位置进行覆盖,同时尾下标后移一位 +// 若尾指针等于切片实际使用长度,则对实际使用量和实际占用量进行判断 +// 当首部还有冗余时则删将实际使用整体前移到首部,否则对尾部进行扩容即可 +//@receiver q *Queue 接受者queue的指针 +//@param e interface{} 待插入元素 +//@return nil +func (q *Queue) Push(e interface{}) { + if q == nil { + q = New() + } + q.mutex.Lock() + if q.end < q.cap { + //不需要扩容 + q.data[q.end] = e + } else { + //需要扩容 + if q.begin > 0 { + //首部有冗余,整体前移 + for i := uint64(0); i < q.end-q.begin; i++ { + q.data[i] = q.data[i+q.begin] + } + q.end -= q.begin + q.begin = 0 + } else { + //冗余不足,需要扩容 + if q.cap <= 65536 { + //容量翻倍 + if q.cap == 0 { + q.cap = 1 + } + q.cap *= 2 + } else { + //容量增加2^16 + q.cap += 2 ^ 16 + } + //复制扩容前的元素 + tmp := make([]interface{}, q.cap, q.cap) + copy(tmp, q.data) + q.data = tmp + } + q.data[q.end] = e + } + q.end++ + q.mutex.Unlock() +} + +//@title Pop +//@description +// 以queue队列容器做接收者 +// 弹出容器第一个元素,同时首下标后移一位 +// 若容器为空,则不进行弹出 +// 弹出结束后,进行缩容判断,考虑到queue的冗余会存在于前后两个方向 +// 所以需要对前后两方分别做判断, 但由于首部主要是减少,并不会增加,所以不需要太多冗余量,而尾部只做添加,所以需要更多的冗余 +// 所以可以对首部预留2^10的冗余,当超过时直接对首部冗余清除即可,释放首部空间时尾部空间仍然保留不变 +// 当首部冗余不足2^10时,但冗余超过实际使用空间,也会对首部进行缩容,尾部不变 +// 同时返回队首元素 +//@receiver q *Queue 接受者queue的指针 +//@param nil +//@return e interface{} 队首元素 +func (q *Queue) Pop() (e interface{}) { + if q == nil { + q = New() + return nil + } + if q.Empty() { + q.Clear() + return nil + } + q.mutex.Lock() + e = q.data[q.begin] + q.begin++ + if q.begin >= 1024 || q.begin*2 > q.end { + //首部冗余超过2^10或首部冗余超过实际使用 + q.cap -= q.begin + q.end -= q.begin + tmp := make([]interface{}, q.cap, q.cap) + copy(tmp, q.data[q.begin:]) + q.data = tmp + q.begin = 0 + } + q.mutex.Unlock() + return e +} + +//@title Front +//@description +// 以queue队列容器做接收者 +// 返回该容器的第一个元素 +// 若该容器当前为空,则返回nil +//@receiver q *Queue 接受者queue的指针 +//@param nil +//@return e interface{} 容器的第一个元素 +func (q *Queue) Front() (e interface{}) { + if q == nil { + q = New() + return nil + } + if q.Empty() { + q.Clear() + return nil + } + return q.data[q.begin] +} + +//@title Back +//@description +// 以queue队列容器做接收者 +// 返回该容器的最后一个元素 +// 若该容器当前为空,则返回nil +//@receiver q *Queue 接受者queue的指针 +//@param nil +//@return e interface{} 容器的最后一个元素 +func (q *Queue) Back() (e interface{}) { + if q == nil { + q = New() + return nil + } + if q.Empty() { + q.Clear() + return nil + } + return q.data[q.end-1] +} diff --git a/data_structure/radix/node.go b/data_structure/radix/node.go new file mode 100644 index 0000000..4921f10 --- /dev/null +++ b/data_structure/radix/node.go @@ -0,0 +1,308 @@ +package radix + +import ( + "strings" +) + +//@Title radix +//@Description +// 前缀基数树的节点 +// 可通过节点的分叉对string进行查找 +// 增添string时候需要增删结点,同时将结点内置的map中增删对应的string即可 +// 当string到终点时存储元素 + +//node树节点结构体 +//该节点是radix的树节点 +//结点存储到此时的string的前缀数量 +//son存储其下属分叉的子结点指针 +//该节点同时存储其元素 +type node struct { + pattern string //到终点时不为"",其他都为"" + part string //以当前结点的string内容 + num int //以当前结点为前缀的数量 + sons map[string]*node //该结点下属结点的指针 + fuzzy bool //模糊匹配?该结点首字符为':'或'*'为模糊匹配 +} + +//@title newNode +//@description +// 新建一个前缀基数树节点并返回 +// 将传入的元素e作为该节点的承载元素 +//@receiver nil +//@param name string 该节点的名字,即其对应的string +//@return n *node 新建的单词查找树节点的指针 +func newNode(part string) (n *node) { + fuzzy := false + if len(part) > 0 { + fuzzy = part[0] == ':' || part[0] == '*' + } + return &node{ + pattern: "", + part: part, + num: 0, + sons: make(map[string]*node), + fuzzy: fuzzy, + } +} + +//@title analysis +//@description +// 将string按'/'进行分段解析 +// 为""部分直接舍弃,返回解析结果 +// 同时按规则重组用以解析是string并返回 +//@receiver nil +//@param s string 待解析的string +//@return ss []string 按'/'进行分层解析后的结果 +//@return newS string 按符合规则解析结果重组后的s +func analysis(s string) (ss []string, newS string) { + vs := strings.Split(s, "/") + ss = make([]string, 0) + newS = "/" + for _, item := range vs { + if item != "" { + ss = append(ss, item) + newS = newS + "/" + item + if item[0] == '*' { + break + } + } + } + return ss, newS +} + +//@title inOrder +//@description +// 以node前缀基数树节点做接收者 +// 遍历其分叉以找到其存储的所有string +//@receiver n *node 接受者node的指针 +//@param s string 到该结点时的前缀string +//@return es []interface{} 以该前缀s为前缀的所有string的集合 +func (n *node) inOrder(s string) (es []interface{}) { + if n == nil { + return es + } + if n.pattern != "" { + es = append(es, s+n.part) + } + for _, son := range n.sons { + es = append(es, son.inOrder(s+n.part+"/")...) + } + return es +} + +//@title insert +//@description +// 以node前缀基数树节点做接收者 +// 从n节点中继续插入以s为索引的元素e,且当前抵达的string位置为p +// 当到达s终点时进行插入,如果此时node承载了string则插入失败,否则成功 +// 当未到达终点时,根据当前抵达的位置去寻找其子结点继续遍历即可 +// 当插入失败且对应子结点为新建节点时则需要删除该子结点 +//@receiver n *node 接受者node的指针 +//@param pattern string 待插入的string整体 +//@param ss []string 待删除元素的索引s的按'/'进行分层的索引集合 +//@param p int 索引当前抵达的位置 +//@return b bool 是否插入成功? +func (n *node) insert(pattern string, ss []string, p int) (b bool) { + if p == len(ss) { + if n.pattern != "" { + //该节点承载了string + return false + } + //成功插入 + n.pattern = pattern + n.num++ + return true + } + //找到该层的string + s := ss[p] + //从其子结点的map中找到对应的方向 + son, ok := n.sons[s] + if !ok { + //不存在,新建并放入map中 + son = newNode(s) + n.sons[s] = son + } + //从子结点对应方向继续插入 + b = son.insert(pattern, ss, p+1) + if b { + n.num++ + } else { + if !ok { + //插入失败且该子节点为新建结点则需要删除该子结点 + delete(n.sons, s) + } + } + return b +} + +//@title erase +//@description +// 以node前缀基数树节点做接收者 +// 从n节点中继续删除以s为索引的元素e,且当前抵达的string位置为p +// 当到达s终点时进行删除,如果此时node未承载元素则删除失败,否则成功 +// 当未到达终点时,根据当前抵达的位置去寻找其子结点继续遍历即可,若其分叉为nil则直接失败 +//@receiver n *node 接受者node的指针 +//@param ss []string 待删除元素的索引s的按'/'进行分层的索引集合 +//@param p int 索引当前抵达的位置 +//@return b bool 是否删除成功? +func (n *node) erase(ss []string, p int) (b bool) { + if p == len(ss) { + if n.pattern != "" { + //该结点承载是string是,删除成功 + n.pattern = "" + n.num-- + return true + } + return false + } + //从map中找到对应下子结点位置并递归进行删除 + s := ss[p] + son, ok := n.sons[s] + if !ok || son == nil { + //未找到或son不存在,删除失败 + return false + } + b = son.erase(ss, p+1) + if b { + n.num-- + if son.num <= 0 { + //删除后子结点的num<=0即该节点无后续存储元素,可以销毁 + delete(n.sons, s) + } + } + return b +} + +//@title delete +//@description +// 以node前缀基数树节点做接收者 +// 从n节点中继续删除以s为索引的元素e,且当前抵达的string位置为p +// 当到达s终点时进行删除,删除所有后续元素,并返回其后续元素的数量 +// 当未到达终点时,根据当前抵达的位置去寻找其子结点继续遍历即可,若其分叉为nil则直接返回0 +//@receiver n *node 接受者node的指针 +//@param ss []string 待删除元素的索引s的按'/'进行分层的索引集合 +//@param p int 索引当前抵达的位置 +//@return num int 被删除元素的数量 +func (n *node) delete(ss []string, p int) (num int) { + if p == len(ss) { + return n.num + } + //从map中找到对应下子结点位置并递归进行删除 + s := ss[p] + son, ok := n.sons[s] + if !ok || son == nil { + return 0 + } + num = son.delete(ss, p+1) + if num > 0 { + son.num -= num + if son.num <= 0 { + //删除后子结点的num<=0即该节点无后续存储元素,可以销毁 + delete(n.sons, s) + } + } + return num +} + +//@title count +//@description +// 以node前缀基数树节点做接收者 +// 从n节点中继续查找以s为前缀索引的元素e,且当前抵达的string位置为p +// 当到达s终点时返回其值即可 +// 当未到达终点时,根据当前抵达的位置去寻找其子结点继续遍历即可,当其分叉为nil则直接返回0 +//@receiver n *node 接受者node的指针 +//@param ss []string 待删除元素的索引s的按'/'进行分层的索引集合 +//@param p int 索引当前抵达的位置 +//@return num int 以该s为前缀的string的数量 +func (n *node) count(ss []string, p int) (num int) { + if p == len(ss) { + return n.num + } + //从map中找到对应下子结点位置并递归进行查找 + s := ss[p] + son, ok := n.sons[s] + if !ok || son == nil { + return 0 + } + return son.count(ss, p+1) +} + +//@title mate +//@description +// 以node前缀基数树节点做接收者 +// 先从radix树的根节点开始找到第一个可以满足该模糊匹配方案的string结点 +// 随后将s和结点的pattern进行模糊映射,将模糊查找的值和匹配值进行映射并返回即可 +// 若该结点未找到则直接返回nil和false即可 +//@receiver n *node 接受者node的指针 +//@param ss []string 待删除元素的索引s的按'/'进行分层的索引集合 +//@param p int 索引当前抵达的位置 +//@return m map[string]string s从结点中利用模糊匹配到的所有key和value的映射 +//@return ok bool 匹配成功? +func (n *node) mate(s string, p int) (m map[string]string, ok bool) { + //解析url + searchParts, _ := analysis(s) + //从该请求类型中寻找对应的路由结点 + q := n.find(searchParts, 0) + if q != nil { + //解析该结点的pattern + parts, _ := analysis(q.pattern) + //动态参数映射表 + params := make(map[string]string) + for index, part := range parts { + if part[0] == ':' { + //动态匹配,将参数名和参数内容的映射放入映射表内 + params[part[1:]] = searchParts[index] + } + if part[0] == '*' && len(part) > 1 { + //通配符,将后续所有内容全部添加到映射表内同时结束遍历 + params[part[1:]] = strings.Join(searchParts[index:], "/") + break + } + } + return params, true + } + return nil, false +} + +//@title find +//@description +// 以node前缀基数树节点做接收者 +// 从radix树的根节点开始找到第一个可以满足该模糊匹配方案的string结点 +// 若该结点未找到则直接返回nil +//@receiver n *node 接受者node的指针 +//@param ss []string 待删除元素的索引s的按'/'进行分层的索引集合 +//@param p int 索引当前抵达的位置 +//@return m map[string]string s从结点中利用模糊匹配到的所有key和value的映射 +//@return ok bool 匹配成功? +func (n *node) find(parts []string, height int) (q *node) { + //根据长度和局部string的首字符进行判断 + if len(parts) == height || strings.HasPrefix(n.part, "*") { + if n.pattern == "" { + //匹配失败,该结点处无匹配的信息 + return nil + } + //匹配成功,返回该结点 + return n + } + //从该结点的所有子结点中查找可用于递归查找的结点 + //当局部string信息和当前层string相同时可用于递归查找 + //当该子结点是动态匹配时也可以用于递归查找 + part := parts[height] + //从所有子结点中找到可用于递归查找的结点 + children := make([]*node, 0, 0) + for _, child := range n.sons { + if child.part == part || child.fuzzy { + //局部string相同或动态匹配 + children = append(children, child) + } + } + for _, child := range children { + //递归查询,并根据结果进行判断 + result := child.find(parts, height+1) + if result != nil { + //存在一个满足时就可以返回 + return result + } + } + return nil +} diff --git a/data_structure/radix/radix.go b/data_structure/radix/radix.go new file mode 100644 index 0000000..a419b5c --- /dev/null +++ b/data_structure/radix/radix.go @@ -0,0 +1,275 @@ +package radix + +//@Title radix +//@Description +// 前缀基数树-radix +// 以多叉树的形式实现,根据'/'进行string分割,将分割后的string数组进行段存储 +// 不存储其他元素,仅对string进行分段存储和模糊匹配 +// 使用互斥锁实现并发控制 + +import ( + "github.com/hlccd/goSTL/utils/iterator" + "sync" +) + +//radix前缀基数树结构体 +//该实例存储前缀基数树的根节点 +//同时保存该树已经存储了多少个元素 +type radix struct { + root *node //前缀基数树的根节点指针 + size int //当前已存放的元素数量 + mutex sync.Mutex //并发控制锁 +} + +//radix前缀基数树容器接口 +//存放了radix前缀基数树可使用的函数 +//对应函数介绍见下方 +type radixer interface { + Iterator() (i *Iterator.Iterator) //返回包含该radix的所有string + Size() (num int) //返回该radix中保存的元素个数 + Clear() //清空该radix + Empty() (b bool) //判断该radix是否为空 + Insert(s string) (b bool) //向radix中插入string + Erase(s string) (b bool) //从radix中删除string + Delete(s string) (num int) //从radix中删除以s为前缀的所有string + Count(s string) (num int) //从radix中寻找以s为前缀的string单词数 + Mate(s string) (m map[string]string, ok bool) //利用radix树中的string对s进行模糊匹配,':'可模糊匹配该层,'*'可模糊匹配后面所有 +} + +//@title New +//@description +// 新建一个radix前缀基数树容器并返回 +// 初始根节点为nil +//@receiver nil +//@param nil +//@return r *radix 新建的radix指针 +func New() (r *radix) { + return &radix{ + root: newNode(""), + size: 0, + mutex: sync.Mutex{}, + } +} + +//@title Iterator +//@description +// 以radix前缀基数树做接收者 +// 将该radix中所有存放的string放入迭代器中并返回 +//@receiver r *radix 接受者radix的指针 +//@param nil +//@return i *iterator.Iterator 新建的Iterator迭代器指针 +func (r *radix) Iterator() (i *Iterator.Iterator) { + if r == nil { + return nil + } + r.mutex.Lock() + es := r.root.inOrder("") + i = Iterator.New(&es) + r.mutex.Unlock() + return i +} + +//@title Size +//@description +// 以radix前缀基数树做接收者 +// 返回该容器当前含有元素的数量 +// 如果容器为nil返回0 +//@receiver r *radix 接受者radix的指针 +//@param nil +//@return num int 容器中实际使用元素所占空间大小 +func (r *radix) Size() (num int) { + if r == nil { + return 0 + } + if r.root == nil { + return 0 + } + return r.size +} + +//@title Clear +//@description +// 以radix前缀基数树做接收者 +// 将该容器中所承载的元素清空 +// 将该容器的size置0 +//@receiver r *radix 接受者radix的指针 +//@param nil +//@return nil +func (r *radix) Clear() { + if r == nil { + return + } + r.mutex.Lock() + r.root = newNode("") + r.size = 0 + r.mutex.Unlock() +} + +//@title Empty +//@description +// 以radix前缀基数树做接收者 +// 判断该radix是否含有元素 +// 如果含有元素则不为空,返回false +// 如果不含有元素则说明为空,返回true +// 如果容器不存在,返回true +//@receiver r *radix 接受者radix的指针 +//@param nil +//@return b bool 该容器是空的吗? +func (r *radix) Empty() (b bool) { + if r == nil { + return true + } + return r.size == 0 +} + +//@title Insert +//@description +// 以radix前缀基数树做接收者 +// 向radix插入string +// 将对string进行解析,按'/'进行分层,':'为首则为模糊匹配该层,'*'为首则为模糊匹配后面所有 +// 已经存在则无法重复插入 +//@receiver r *radix 接受者radix的指针 +//@param s string 待插入string +//@return b bool 添加成功? +func (r *radix) Insert(s string) (b bool) { + if r == nil { + return false + } + //解析s并按规则重构s + ss, s := analysis(s) + r.mutex.Lock() + if r.root == nil { + //避免根节点为nil + r.root = newNode("") + } + //从根节点开始插入 + b = r.root.insert(s, ss, 0) + if b { + //插入成功,size+1 + r.size++ + } + r.mutex.Unlock() + return b +} + +//@title Erase +//@description +// 以radix前缀基数树做接收者 +// 从radix树中删除元素string +//@receiver r *radix 接受者radix的指针 +//@param s string 待删除的string +//@return b bool 删除成功? +func (r *radix) Erase(s string) (b bool) { + if r.Empty() { + return false + } + if len(s) == 0 { + return false + } + if r.root == nil { + //根节点为nil即无法删除 + return false + } + //解析s并按规则重构s + ss, _ := analysis(s) + r.mutex.Lock() + //从根节点开始删除 + b = r.root.erase(ss, 0) + if b { + //删除成功,size-1 + r.size-- + if r.size == 0 { + //所有string都被删除,根节点置为nil + r.root = nil + } + } + r.mutex.Unlock() + return b +} + +//@title Delete +//@description +// 以radix前缀基数树做接收者 +// 从radix树中删除以s为前缀的所有string +//@receiver r *radix 接受者radix的指针 +//@param s string 待删除string的前缀 +//@return num int 被删除的元素的数量 +func (r *radix) Delete(s string) (num int) { + if r.Empty() { + return 0 + } + if len(s) == 0 { + return 0 + } + if r.root == nil { + return 0 + } + //解析s并按规则重构s + ss, _ := analysis(s) + r.mutex.Lock() + //从根节点开始删除 + num = r.root.delete(ss, 0) + if num > 0 { + //删除成功 + r.size -= num + if r.size <= 0 { + //所有string都被删除,根节点置为nil + r.root = nil + } + } + r.mutex.Unlock() + return num +} + +//@title Count +//@description +// 以radix前缀基数树做接收者 +// 从radix中查找以s为前缀的所有string的个数 +// 如果存在以s为前缀的则返回大于0的值即其数量 +// 如果未找到则返回0 +//@receiver r *radix 接受者radix的指针 +//@param s string 待查找的前缀s +//@return num int 待查找前缀在radix树中存在的数量 +func (r *radix) Count(s string) (num int) { + if r.Empty() { + return 0 + } + if r.root == nil { + return 0 + } + if len(s) == 0 { + return 0 + } + //解析s并按规则重构s + ss, _ := analysis(s) + r.mutex.Lock() + num = r.root.count(ss, 0) + r.mutex.Unlock() + return num +} + +//@title Mate +//@description +// 以radix前缀基数树做接收者 +// 从radix中查找以s为信息的第一个可以模糊匹配到的key和value的映射表 +// key是radix树中的段名,value是s中的段名 +// 如果未找到则返回nil和false +// 否则返回一个映射表和true +//@receiver r *radix 接受者radix的指针 +//@param s string 待查找的信息s +//@return m map[string]string s从前缀基数树中利用模糊匹配到的所有key和value的映射 +//@return ok bool 匹配成功? +func (r *radix) Mate(s string) (m map[string]string, ok bool) { + if r.Empty() { + return nil, false + } + if len(s) == 0 { + return nil, false + } + if r.root == nil { + return nil, false + } + //将s按'/'进行分割,并去掉第一个即去掉"",随后一次按照分层结果进行查找 + m, ok = r.root.mate(s, 0) + return m, ok +} diff --git a/data_structure/ring/node.go b/data_structure/ring/node.go new file mode 100644 index 0000000..6bf20c0 --- /dev/null +++ b/data_structure/ring/node.go @@ -0,0 +1,170 @@ +package ring + +//@Title ring +//@Description +// ring环容器包 +// 该部分包含了环的节点 +// 环的增删都通过节点的增删完成 +// 结点间可插入其前后节点,并同时将两结点建立连接 + +//环的node节点结构体 +//pre和next是该节点的前后两个节点的指针 +//用以保证环整体是相连的 +type node struct { + data interface{} //结点所承载的元素 + pre *node //前结点指针 + next *node //后结点指针 +} + +//node结点容器接口 +//存放了node容器可使用的函数 +//对应函数介绍见下方 + +type noder interface { + preNode() (m *node) //返回前结点指针 + nextNode() (m *node) //返回后结点指针 + insertPre(pre *node) //在该结点前插入结点并建立连接 + insertNext(next *node) //在该结点后插入结点并建立连接 + erase() //删除该结点,并使该结点前后两结点建立连接 + value() (e interface{}) //返回该结点所承载的元素 + setValue(e interface{}) //修改该结点承载元素为e +} + +//@title newNode +//@description +// 新建一个自环结点并返回其指针 +// 初始首结点的前后结点指针都为自身 +//@receiver nil +//@param nil +//@return n *node 新建的node指针 +func newNode(e interface{}) (n *node) { + n = &node{ + data: e, + pre: nil, + next: nil, + } + n.pre = n + n.next = n + return n +} + +//@title preNode +//@description +// 以node结点做接收者 +// 返回该结点的前结点 +//@receiver n *node 接收者的node指针 +//@param nil +//@return pre *node 该结点的前结点指针 +func (n *node) preNode() (pre *node) { + if n == nil { + return + } + return n.pre +} + +//@title nextNode +//@description +// 以node结点做接收者 +// 返回该结点的后结点 +//@receiver n *node 接收者的node指针 +//@param nil +//@return next *node 该结点的后结点指针 +func (n *node) nextNode() (next *node) { + if n == nil { + return + } + return n.next +} + +//@title insertPre +//@description +// 以node结点做接收者 +// 对该结点插入前结点 +// 并建立前结点和该结点之间的连接 +//@receiver n *node 接收者的node指针 +//@param pre *node 该结点的前结点指针 +//@return nil +func (n *node) insertPre(pre *node) { + if n == nil || pre == nil { + return + } + pre.next = n + pre.pre = n.pre + if n.pre != nil { + n.pre.next = pre + } + n.pre = pre +} + +//@title insertNext +//@description +// 以node结点做接收者 +// 对该结点插入后结点 +// 并建立后结点和该结点之间的连接 +//@receiver n *node 接收者的node指针 +//@param next *node 该结点的后结点指针 +//@return nil +func (n *node) insertNext(next *node) { + if n == nil || next == nil { + return + } + next.pre = n + next.next = n.next + if n.next != nil { + n.next.pre = next + } + n.next = next +} + +//@title erase +//@description +// 以node结点做接收者 +// 销毁该结点 +// 同时建立该节点前后节点之间的连接 +//@receiver n *node 接收者的node指针 +//@param nil +//@return nil +func (n *node) erase() { + if n == nil { + return + } + if n.pre == nil && n.next == nil { + return + } else if n.pre == nil { + n.next.pre = nil + } else if n.next == nil { + n.pre.next = nil + } else { + n.pre.next = n.next + n.next.pre = n.pre + } + n = nil +} + +//@title value +//@description +// 以node结点做接收者 +// 返回该结点所要承载的元素 +//@receiver n *node 接收者的node指针 +//@param nil +//@return e interface{} 该节点所承载的元素e +func (n *node) value() (e interface{}) { + if n == nil { + return nil + } + return n.data +} + +//@title setValue +//@description +// 以node结点做接收者 +// 对该结点设置其承载的元素 +//@receiver n *node 接收者的node指针 +//@param e interface{} 该节点所要承载的元素e +//@return nil +func (n *node) setValue(e interface{}) { + if n == nil { + return + } + n.data = e +} diff --git a/data_structure/ring/ring.go b/data_structure/ring/ring.go new file mode 100644 index 0000000..c8b9b58 --- /dev/null +++ b/data_structure/ring/ring.go @@ -0,0 +1,271 @@ +package ring + +//@Title ring +//@Description +// ring环容器包 +// 环将所有结点通过指针的方式串联起来,从而使得其整体保持一个线性状态 +// 不同于链表首尾不相连的情况,环将首尾结点连接起来,从而摒弃孤立的首尾结点 +// 可以利用其中的任何一个结点遍历整个环,也可以在任何位置进行插入 +// 增删结点需要同步修改其相邻的元素的前后指针以保证其整体是联通的 +// 可接纳不同类型的元素 +// 通过并发控制锁保证了在高并发过程中的数据一致性 + +import ( + "github.com/hlccd/goSTL/utils/iterator" + "sync" +) + +//ring环结构体 +//包含环的头尾节点指针 +//当增删结点时只需要移动到对应位置进行操作即可 +//当一个节点进行增删时需要同步修改其临接结点的前后指针 +//结构体中记录该环中当前所持有的结点的指针即可 +//同时记录该环中存在多少元素即size +//使用并发控制锁以保证数据一致性 +type Ring struct { + now *node //环当前持有的结点指针 + size uint64 //当前存储的元素个数 + mutex sync.Mutex //并发控制锁 +} + +//ring环容器接口 +//存放了ring容器可使用的函数 +//对应函数介绍见下方 + +type ringer interface { + Iterator() (i *Iterator.Iterator) //创建一个包含环中所有元素的迭代器并返回其指针 + Size() (size uint64) //返回环所承载的元素个数 + Clear() //清空该环 + Empty() (b bool) //判断该环是否位空 + Insert(e interface{}) //向环当前位置后方插入元素e + Erase() //删除当前结点并持有下一结点 + Value() (e interface{}) //返回当前持有结点的元素 + Set(e interface{}) //在当前结点设置其承载的元素为e + Next() //持有下一节点 + Pre() //持有上一结点 +} + +//@title New +//@description +// 新建一个ring环容器并返回 +// 初始持有的结点不存在,即为nil +// 初始size为0 +//@receiver nil +//@param nil +//@return r *Ring 新建的ring指针 +func New() (r *Ring) { + return &Ring{ + now: nil, + size: 0, + mutex: sync.Mutex{}, + } +} + +//@title Iterator +//@description +// 以ring环容器做接收者 +// 将ring环容器中所承载的元素放入迭代器中 +// 从该结点开始向后遍历获取全部承载的元素 +//@receiver r *Ring 接收者的ring指针 +//@param nil +//@return i *iterator.Iterator 新建的Iterator迭代器指针 +func (r *Ring) Iterator() (i *Iterator.Iterator) { + if r == nil { + r = New() + } + r.mutex.Lock() + //将所有元素复制出来放入迭代器中 + tmp := make([]interface{}, r.size, r.size) + //从当前结点开始向后遍历 + for n, idx := r.now, uint64(0); n != nil && idx < r.size; n, idx = n.nextNode(), idx+1 { + tmp[idx] = n.value() + } + i = Iterator.New(&tmp) + r.mutex.Unlock() + return i +} + +//@title Size +//@description +// 以ring环容器做接收者 +// 返回该容器当前含有元素的数量 +//@receiver r *Ring 接收者的ring指针 +//@param nil +//@return num int 容器中所承载的元素数量 +func (r *Ring) Size() (size uint64) { + if r == nil { + r = New() + } + return r.size +} + +//@title Clear +//@description +// 以ring环容器做接收者 +// 将该容器中所承载的元素清空 +// 将该容器的当前持有的结点置为nil,长度初始为0 +//@receiver r *Ring 接收者的ring指针 +//@param nil +//@return nil +func (r *Ring) Clear() { + if r == nil { + r = New() + } + r.mutex.Lock() + //销毁环 + r.now = nil + r.size = 0 + r.mutex.Unlock() +} + +//@title Empty +//@description +// 以ring环容器做接收者 +// 判断该ring环容器是否含有元素 +// 该判断过程通过size进行判断,size为0则为true,否则为false +//@receiver r *Ring 接收者的ring指针 +//@param nil +//@return b bool 该容器是空的吗? +func (r *Ring) Empty() (b bool) { + if r == nil { + r = New() + } + return r.size == 0 +} + +//@title Insert +//@description +// 以ring环容器做接收者 +// 通过环中当前持有的结点进行添加 +// 如果环为建立,则新建一个自环结点设为环 +// 存在持有的结点,则在其后方添加即可 +//@receiver r *Ring 接收者的ring指针 +//@param e interface{} 待插入元素 +//@return nil +func (r *Ring) Insert(e interface{}) { + if r == nil { + r = New() + } + r.mutex.Lock() + //新建自环结点 + n := newNode(e) + if r.size == 0 { + //原本无环,设为新环 + r.now = n + } else { + //持有结点,在后方插入 + r.now.insertNext(n) + } + r.size++ + r.mutex.Unlock() +} + +//@title Erase +//@description +// 以ring环容器做接收者 +// 先判断是否仅持有一个结点 +// 若仅有一个结点,则直接销毁环 +// 否则将当前持有结点设为下一节点,并前插原持有结点的前结点即可 +//@receiver r *Ring 接收者的ring指针 +//@param nil +//@return nil +func (r *Ring) Erase() { + if r == nil { + r = New() + } + if r.size == 0 { + return + } + r.mutex.Lock() + //删除开始 + if r.size == 1 { + //环内仅有一个结点,销毁环即可 + r.now = nil + } else { + //环内还有其他结点,将持有结点后移一位 + //后移后将当前结点前插原持有结点的前结点 + r.now = r.now.nextNode() + r.now.insertPre(r.now.preNode().preNode()) + } + r.size-- + r.mutex.Unlock() +} + +//@title Value +//@description +// 以ring环容器做接收者 +// 获取环中当前持有节点所承载的元素 +// 若环中持有的结点不存在,直接返回nil +//@receiver r *Ring 接收者的ring指针 +//@param nil +//@return e interface{} 获取的元素 +func (r *Ring) Value() (e interface{}) { + if r == nil { + r = New() + } + if r.now == nil { + //无持有结点,直接返回nil + return nil + } + return r.now.value() +} + +//@title Set +//@description +// 以ring环容器做接收者 +// 修改当前持有结点所承载的元素 +// 若未持有结点,直接结束即可 +//@receiver r *Ring 接收者的ring指针 +//@param e interface{} 修改后当元素 +//@return nil +func (r *Ring) Set(e interface{}) { + if r == nil { + r = New() + } + if r.now == nil { + return + } + r.mutex.Lock() + r.now.setValue(e) + r.mutex.Unlock() +} + +//@title Next +//@description +// 以ring环容器做接收者 +// 将当前持有的结点后移一位 +// 若当前无持有结点,则直接结束 +//@receiver r *Ring 接收者的ring指针 +//@param nil +//@return nil +func (r *Ring) Next() { + if r == nil { + r = New() + } + if r.now == nil { + return + } + r.mutex.Lock() + r.now = r.now.nextNode() + r.mutex.Unlock() +} + +//@title Pre +//@description +// 以ring环容器做接收者 +// 将当前持有的结点前移一位 +// 若当前无持有结点,则直接结束 +//@receiver r *Ring 接收者的ring指针 +//@param nil +//@return nil +func (r *Ring) Pre() { + if r == nil { + r = New() + } + if r.size == 0 { + return + } + r.mutex.Lock() + r.now = r.now.preNode() + r.mutex.Unlock() +} diff --git a/data_structure/stack/stack.go b/data_structure/stack/stack.go new file mode 100644 index 0000000..5fa6666 --- /dev/null +++ b/data_structure/stack/stack.go @@ -0,0 +1,236 @@ +package stack + +//@Title stack +//@Description +// stack栈容器包 +// 以动态数组的形式实现,扩容方式同vector +// 该容器可以在顶部实现线性增减元素 +// 通过interface实现泛型,可接纳不同类型的元素 +// 互斥锁实现并发控制 +import ( + "github.com/hlccd/goSTL/utils/iterator" + "sync" +) + +//stack栈结构体 +//包含动态数组和该数组的顶部指针 +//顶部指针指向实际顶部元素的下一位置 +//当删除节点时仅仅需要下移顶部指针一位即可 +//当新增结点时优先利用冗余空间 +//当冗余空间不足时先倍增空间至2^16,超过后每次增加2^16的空间 +//删除结点后如果冗余超过2^16,则释放掉 +//删除后若冗余量超过使用量,也释放掉冗余空间 +type Stack struct { + data []interface{} //用于存储元素的动态数组 + top uint64 //顶部指针 + cap uint64 //动态数组的实际空间 + mutex sync.Mutex //并发控制锁 +} + +//stack栈容器接口 +//存放了stack容器可使用的函数 +//对应函数介绍见下方 +type stacker interface { + Iterator() (i *Iterator.Iterator) //返回一个包含栈中所有元素的迭代器 + Size() (num uint64) //返回该栈中元素的使用空间大小 + Clear() //清空该栈容器 + Empty() (b bool) //判断该栈容器是否为空 + Push(e interface{}) //将元素e添加到栈顶 + Pop() //弹出栈顶元素 + Top() (e interface{}) //返回栈顶元素 +} + +//@title New +//@description +// 新建一个stack栈容器并返回 +// 初始stack的动态数组容量为1 +// 初始stack的顶部指针置0,容量置1 +//@receiver nil +//@param nil +//@return s *Stack 新建的stack指针 +func New() (s *Stack) { + return &Stack{ + data: make([]interface{}, 1, 1), + top: 0, + cap: 1, + mutex: sync.Mutex{}, + } +} + +//@title Iterator +//@description +// 以stack栈容器做接收者 +// 将stack栈容器中不使用空间释放掉 +// 返回一个包含容器中所有使用元素的迭代器 +//@receiver s *Stack 接受者stack的指针 +//@param nil +//@return i *iterator.Iterator 新建的Iterator迭代器指针 +func (s *Stack) Iterator() (i *Iterator.Iterator) { + if s == nil { + s = New() + } + s.mutex.Lock() + if s.data == nil { + //data不存在,新建一个 + s.data = make([]interface{}, 1, 1) + s.top = 0 + s.cap = 1 + } else if s.top < s.cap { + //释放未使用的空间 + tmp := make([]interface{}, s.top, s.top) + copy(tmp, s.data) + s.data = tmp + } + //创建迭代器 + i = Iterator.New(&s.data) + s.mutex.Unlock() + return i +} + +//@title Size +//@description +// 以stack栈容器做接收者 +// 返回该容器当前含有元素的数量 +//@receiver s *Stack 接受者stack的指针 +//@param nil +//@return num int 容器中实际使用元素所占空间大小 +func (s *Stack) Size() (num uint64) { + if s == nil { + s = New() + } + return s.top +} + +//@title Clear +//@description +// 以stack栈容器做接收者 +// 将该容器中所承载的元素清空 +// 将该容器的尾指针置0 +//@receiver s *Stack 接受者stack的指针 +//@param nil +//@return nil +func (s *Stack) Clear() { + if s == nil { + s = New() + } + s.mutex.Lock() + s.data = make([]interface{}, 0, 0) + s.top = 0 + s.cap = 1 + s.mutex.Unlock() +} + +//@title Empty +//@description +// 以stack栈容器做接收者 +// 判断该stack栈容器是否含有元素 +// 如果含有元素则不为空,返回false +// 如果不含有元素则说明为空,返回true +// 如果容器不存在,返回true +// 该判断过程通过顶部指针数值进行判断 +// 当顶部指针数值为0时说明不含有元素 +// 当顶部指针数值大于0时说明含有元素 +//@receiver s *Stack 接受者stack的指针 +//@param nil +//@return b bool 该容器是空的吗? +func (s *Stack) Empty() (b bool) { + if s == nil { + return true + } + return s.Size() == 0 +} + +//@title Push +//@description +// 以stack栈容器做接收者 +// 在容器顶部插入元素 +// 若存储冗余空间,则在顶部指针位插入元素,随后上移顶部指针 +// 否则进行扩容,扩容后获得冗余空间重复上一步即可。 +//@receiver s *Stack 接受者stack的指针 +//@param e interface{} 待插入顶部的元素 +//@return nil +func (s *Stack) Push(e interface{}) { + if s == nil { + s = New() + } + s.mutex.Lock() + if s.top < s.cap { + //还有冗余,直接添加 + s.data[s.top] = e + } else { + //冗余不足,需要扩容 + if s.cap <= 65536 { + //容量翻倍 + if s.cap == 0 { + s.cap = 1 + } + s.cap *= 2 + } else { + //容量增加2^16 + s.cap += 65536 + } + //复制扩容前的元素 + tmp := make([]interface{}, s.cap, s.cap) + copy(tmp, s.data) + s.data = tmp + s.data[s.top] = e + } + s.top++ + s.mutex.Unlock() +} + +//@title Pop +//@description +// 以stack栈容器做接收者 +// 弹出容器顶部元素,同时顶部指针下移一位 +// 当顶部指针小于容器切片实际使用空间的一半时,重新分配空间释放未使用部分 +// 若容器为空,则不进行弹出 +//@receiver s *Stack 接受者stack的指针 +//@param nil +//@return nil +func (s *Stack) Pop() { + if s == nil { + s = New() + return + } + if s.Empty() { + return + } + s.mutex.Lock() + s.top-- + if s.cap-s.top >= 65536 { + //容量和实际使用差值超过2^16时,容量直接减去2^16 + s.cap -= 65536 + tmp := make([]interface{}, s.cap, s.cap) + copy(tmp, s.data) + s.data = tmp + } else if s.top*2 < s.cap { + //实际使用长度是容量的一半时,进行折半缩容 + s.cap /= 2 + tmp := make([]interface{}, s.cap, s.cap) + copy(tmp, s.data) + s.data = tmp + } + s.mutex.Unlock() +} + +//@title Top +//@description +// 以stack栈容器做接收者 +// 返回该容器的顶部元素 +// 若该容器当前为空,则返回nil +//@receiver s *Stack 接受者stack的指针 +//@param nil +//@return e interface{} 容器的顶部元素 +func (s *Stack) Top() (e interface{}) { + if s == nil { + return nil + } + if s.Empty() { + return nil + } + s.mutex.Lock() + e = s.data[s.top-1] + s.mutex.Unlock() + return e +} diff --git a/data_structure/treap/node.go b/data_structure/treap/node.go new file mode 100644 index 0000000..1b24baa --- /dev/null +++ b/data_structure/treap/node.go @@ -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 +} \ No newline at end of file diff --git a/data_structure/treap/treap.go b/data_structure/treap/treap.go new file mode 100644 index 0000000..e2ca20f --- /dev/null +++ b/data_structure/treap/treap.go @@ -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 +} \ No newline at end of file diff --git a/data_structure/trie/node.go b/data_structure/trie/node.go new file mode 100644 index 0000000..a7a6543 --- /dev/null +++ b/data_structure/trie/node.go @@ -0,0 +1,243 @@ +package trie + +//@Title trie +//@Description +// 单词查找树的节点 +// 可通过节点的分叉对string进行查找 +// 增添string时候只需要增删结点即可 +// 当string到终点时存储元素 + +//node树节点结构体 +//该节点是trie的树节点 +//结点存储到此时的string的前缀数量 +//以son为分叉存储下属的string +//该节点同时存储其元素 +type node struct { + num int //以当前结点为前缀的string的数量 + son [64]*node //分叉 + value interface{} //当前结点承载的元素 +} + +//@title newNode +//@description +// 新建一个单词查找树节点并返回 +// 将传入的元素e作为该节点的承载元素 +//@receiver nil +//@param e interface{} 承载元素e +//@return n *node 新建的单词查找树节点的指针 +func newNode(e interface{}) (n *node) { + return &node{ + num: 0, + value: e, + } +} + +//@title inOrder +//@description +// 以node单词查找树节点做接收者 +// 遍历其分叉以找到其存储的所有string +//@receiver n *node 接受者node的指针 +//@param s string 到该结点时的前缀string +//@return es []interface{} 以该前缀s为前缀的所有string的集合 +func (n *node) inOrder(s string) (es []interface{}) { + if n == nil { + return es + } + if n.value != nil { + es = append(es, s) + } + for i, p := 0, 0; i < 62 && p < n.num; i++ { + if n.son[i] != nil { + if i < 26 { + es = append(es, n.son[i].inOrder(s+string(i+'a'))...) + } else if i < 52 { + es = append(es, n.son[i].inOrder(s+string(i-26+'A'))...) + } else { + es = append(es, n.son[i].inOrder(s+string(i-52+'0'))...) + } + p++ + } + } + return es +} + +//@title getIdx +//@description +// 传入一个byte并根据其值返回其映射到分叉的值 +// 当不属于'a'~'z','A'~'Z','0'~'9','+','/'时返回-1 +//@receiver nil +//@param c byte 待映射的ASCII码 +//@return idx int 以c映射出的分叉下标 +func getIdx(c byte) (idx int) { + if c >= 'a' && c <= 'z' { + idx = int(c - 'a') + } else if c >= 'A' && c <= 'Z' { + idx = int(c-'A') + 26 + } else if c >= '0' && c <= '9' { + idx = int(c-'0') + 52 + } else if c == '+' { + idx = 62 + } else if c == '/' { + idx = 63 + } else { + idx = -1 + } + return idx +} + +//@title insert +//@description +// 以node单词查找树节点做接收者 +// 从n节点中继续插入以s为索引的元素e,且当前抵达的string位置为p +// 当到达s终点时进行插入,如果此时node承载了元素则插入失败,否则成功 +// 当未到达终点时,根据当前抵达的位置去寻找其子结点继续遍历即可 +//@receiver n *node 接受者node的指针 +//@param s string 待插入元素的索引s +//@param p int 索引当前抵达的位置 +//@param e interface{} 待插入元素e +//@return b bool 是否插入成功? +func (n *node) insert(s string, p int, e interface{}) (b bool) { + if p == len(s) { + if n.value != nil { + return false + } + n.value = e + n.num++ + return true + } + idx := getIdx(s[p]) + if idx == -1 { + return false + } + ok := true + if n.son[idx] == nil { + //判断该子结点是否存在 + n.son[idx] = newNode(nil) + ok = false + } + b = n.son[idx].insert(s, p+1, e) + if b { + n.num++ + } else { + if !ok { + //插入失败且该子节点为新建结点则需要删除该子结点 + n.son[idx] = nil + } + } + return b +} + +//@title erase +//@description +// 以node单词查找树节点做接收者 +// 从n节点中继续删除以s为索引的元素e,且当前抵达的string位置为p +// 当到达s终点时进行删除,如果此时node未承载元素则删除失败,否则成功 +// 当未到达终点时,根据当前抵达的位置去寻找其子结点继续遍历即可,若其分叉为nil则直接失败 +//@receiver n *node 接受者node的指针 +//@param s string 待删除元素的索引s +//@param p int 索引当前抵达的位置 +//@return b bool 是否删除成功? +func (n *node) erase(s string, p int) (b bool) { + if p == len(s) { + if n.value != nil { + n.value = nil + n.num-- + return true + } + return false + } + idx := getIdx(s[p]) + if idx == -1 { + return false + } + if n.son[idx] == nil { + return false + } + b = n.son[idx].erase(s, p+1) + if b { + n.num-- + if n.son[idx].num == 0 { + n.son[idx] = nil + } + } + return b +} + +//@title delete +//@description +// 以node单词查找树节点做接收者 +// 从n节点中继续删除以s为索引的元素e,且当前抵达的string位置为p +// 当到达s终点时进行删除,删除所有后续元素,并返回其后续元素的数量 +// 当未到达终点时,根据当前抵达的位置去寻找其子结点继续遍历即可,若其分叉为nil则直接返回0 +//@receiver n *node 接受者node的指针 +//@param s string 待删除元素的索引s +//@param p int 索引当前抵达的位置 +//@return num int 被删除元素的数量 +func (n *node) delete(s string, p int) (num int) { + if p == len(s) { + return n.num + } + idx := getIdx(s[p]) + if idx == -1 { + return 0 + } + if n.son[idx] == nil { + return 0 + } + num = n.son[idx].delete(s, p+1) + if num > 0 { + n.num -= num + if n.son[idx].num <= 0 { + n.son[idx] = nil + } + } + return num +} + +//@title count +//@description +// 以node单词查找树节点做接收者 +// 从n节点中继续查找以s为前缀索引的元素e,且当前抵达的string位置为p +// 当到达s终点时返回其值即可 +// 当未到达终点时,根据当前抵达的位置去寻找其子结点继续遍历即可,当其分叉为nil则直接返回0 +//@receiver n *node 接受者node的指针 +//@param s string 待查找元素的前缀索引 +//@param p int 索引当前抵达的位置 +//@return num int 以该s为前缀的string的数量 +func (n *node) count(s string, p int) (num int) { + if p == len(s) { + return n.num + } + idx := getIdx(s[p]) + if idx == -1 { + return 0 + } + if n.son[idx] == nil { + return 0 + } + return n.son[idx].count(s, p+1) +} + +//@title find +//@description +// 以node单词查找树节点做接收者 +// 从n节点中继续查找以s为前缀索引的元素e,且当前抵达的string位置为p +// 当到达s终点时返回其承载的元素即可 +// 当未到达终点时,根据当前抵达的位置去寻找其子结点继续遍历即可,当其分叉为nil则直接返回nil +//@receiver n *node 接受者node的指针 +//@param s string 待查找元素的前缀索引 +//@param p int 索引当前抵达的位置 +//@return e interface{} 该索引所指向的元素e +func (n *node) find(s string, p int) (e interface{}) { + if p == len(s) { + return n.value + } + idx := getIdx(s[p]) + if idx == -1 { + return nil + } + if n.son[idx] == nil { + return nil + } + return n.son[idx].find(s, p+1) +} diff --git a/data_structure/trie/trie.go b/data_structure/trie/trie.go new file mode 100644 index 0000000..90f38e1 --- /dev/null +++ b/data_structure/trie/trie.go @@ -0,0 +1,281 @@ +package trie + +//@Title trie +//@Description +// 单词查找树-Trie +// 以多叉树的形式实现,本次实现中有64叉,即a~z,A~Z,0~9,'+','/'共64个,对应base64的字符 +// 当存储的string中出现其他字符则无法存储 +// 存储的string可以携带一个元素 +// 结点不允许覆盖,即插入值已经存在时会插入失败,需要先删除原值 +// 使用互斥锁实现并发控制 + +import ( + "github.com/hlccd/goSTL/utils/iterator" + "sync" +) + +//trie单词查找树结构体 +//该实例存储单词查找树的根节点 +//同时保存该树已经存储了多少个元素 +//整个树不允许重复插入,若出现重复插入则直接失败 +type trie struct { + root *node //根节点指针 + size int //存放的元素数量 + mutex sync.Mutex //并发控制锁 +} + +//trie单词查找树容器接口 +//存放了trie单词查找树可使用的函数 +//对应函数介绍见下方 +type trieer interface { + Iterator() (i *Iterator.Iterator) //返回包含该trie的所有string + Size() (num int) //返回该trie中保存的元素个数 + Clear() //清空该trie + Empty() (b bool) //判断该trie是否为空 + Insert(s string, e interface{}) (b bool) //向trie中插入string并携带元素e + Erase(s string) (b bool) //从trie中删除以s为索引的元素e + Delete(s string) (num int) //从trie中删除以s为前缀的所有元素 + Count(s string) (num int) //从trie中寻找以s为前缀的string单词数 + Find(s string) (e interface{}) //从trie中寻找以s为索引的元素e +} + +//@title New +//@description +// 新建一个trie单词查找树容器并返回 +// 初始根节点为nil +//@receiver nil +//@param nil +//@return t *trie 新建的trie指针 +func New() (t *trie) { + return &trie{ + root: newNode(nil), + size: 0, + mutex: sync.Mutex{}, + } +} + +//@title Iterator +//@description +// 以trie单词查找树做接收者 +// 将该trie中所有存放的string放入迭代器中并返回 +//@receiver t *trie 接受者trie的指针 +//@param nil +//@return i *iterator.Iterator 新建的Iterator迭代器指针 +func (t *trie) Iterator() (i *Iterator.Iterator) { + if t == nil { + return nil + } + t.mutex.Lock() + //找到trie中存在的所有string + es := t.root.inOrder("") + i = Iterator.New(&es) + t.mutex.Unlock() + return i +} + +//@title Size +//@description +// 以trie单词查找树做接收者 +// 返回该容器当前含有元素的数量 +// 如果容器为nil返回0 +//@receiver t *trie 接受者trie的指针 +//@param nil +//@return num int 容器中实际使用元素所占空间大小 +func (t *trie) Size() (num int) { + if t == nil { + return 0 + } + return t.size +} + +//@title Clear +//@description +// 以trie单词查找树做接收者 +// 将该容器中所承载的元素清空 +// 将该容器的size置0 +//@receiver t *trie 接受者trie的指针 +//@param nil +//@return nil +func (t *trie) Clear() { + if t == nil { + return + } + t.mutex.Lock() + t.root = newNode(nil) + t.size = 0 + t.mutex.Unlock() +} + +//@title Empty +//@description +// 以trie单词查找树做接收者 +// 判断该trie是否含有元素 +// 如果含有元素则不为空,返回false +// 如果不含有元素则说明为空,返回true +// 如果容器不存在,返回true +//@receiver t *trie 接受者trie的指针 +//@param nil +//@return b bool 该容器是空的吗? +func (t *trie) Empty() (b bool) { + if t == nil { + return true + } + return t.size == 0 +} + +//@title Insert +//@description +// 以trie单词查找树做接收者 +// 向trie插入以string类型的s为索引的元素e +// 若存在重复的s则插入失败,不允许覆盖 +// 否则插入成功 +//@receiver t *trie 接受者trie的指针 +//@param s string 待插入元素的索引s +//@param e interface{} 待插入元素e +//@return b bool 添加成功? +func (t *trie) Insert(s string, e interface{}) (b bool) { + if t == nil { + return + } + if len(s) == 0 { + return false + } + t.mutex.Lock() + if t.root == nil { + //避免根节点为nil + t.root = newNode(nil) + } + //从根节点开始插入 + b = t.root.insert(s, 0, e) + if b { + //插入成功,size+1 + t.size++ + } + t.mutex.Unlock() + return b +} + +//@title Erase +//@description +// 以trie单词查找树做接收者 +// 从trie树中删除元素以s为索引的元素e +//@receiver t *trie 接受者trie的指针 +//@param s string 待删除元素的索引 +//@return b bool 删除成功? +func (t *trie) Erase(s string) (b bool) { + if t == nil { + return false + } + if t.Empty() { + return false + } + if len(s) == 0 { + //长度为0无法删除 + return false + } + if t.root == nil { + //根节点为nil即无法删除 + return false + } + t.mutex.Lock() + //从根节点开始删除 + b = t.root.erase(s, 0) + if b { + //删除成功,size-1 + t.size-- + if t.size == 0 { + //所有string都被删除,根节点置为nil + t.root = nil + } + } + t.mutex.Unlock() + return b +} + +//@title Delete +//@description +// 以trie单词查找树做接收者 +// 从trie树中删除以s为前缀的所有元素 +//@receiver t *trie 接受者trie的指针 +//@param s string 待删除元素的前缀 +//@return num int 被删除的元素的数量 +func (t *trie) Delete(s string) (num int) { + if t == nil { + return 0 + } + if t.Empty() { + return 0 + } + if len(s) == 0 { + //长度为0无法删除 + return 0 + } + if t.root == nil { + //根节点为nil即无法删除 + return 0 + } + t.mutex.Lock() + //从根节点开始删除 + num = t.root.delete(s, 0) + if num > 0 { + //删除成功 + t.size -= num + if t.size <= 0 { + //所有string都被删除,根节点置为nil + t.root = nil + } + } + t.mutex.Unlock() + return num +} + +//@title Count +//@description +// 以trie单词查找树做接收者 +// 从trie中查找以s为前缀的所有string的个数 +// 如果存在以s为前缀的则返回大于0的值即其数量 +// 如果未找到则返回0 +//@receiver t *trie 接受者trie的指针 +//@param s string 待查找的前缀s +//@return num int 待查找前缀在trie树中存在的数量 +func (t *trie) Count(s string) (num int) { + if t == nil { + return 0 + } + if t.Empty() { + return 0 + } + if t.root == nil { + return 0 + } + t.mutex.Lock() + //统计所有以s为前缀的string的数量并返回 + num = int(t.root.count(s, 0)) + t.mutex.Unlock() + return num +} + +//@title Find +//@description +// 以trie单词查找树做接收者 +// 从trie中查找以s为索引的元素e,找到则返回e +// 如果未找到则返回nil +//@receiver t *trie 接受者trie的指针 +//@param s string 待查找索引s +//@return ans interface{} 待查找索引所指向的元素 +func (t *trie) Find(s string) (e interface{}) { + if t == nil { + return nil + } + if t.Empty() { + return nil + } + if t.root == nil { + return nil + } + t.mutex.Lock() + //从根节点开始查找以s为索引的元素e + e = t.root.find(s, 0) + t.mutex.Unlock() + return e +} diff --git a/data_structure/vector/vector.go b/data_structure/vector/vector.go new file mode 100644 index 0000000..9b3c78d --- /dev/null +++ b/data_structure/vector/vector.go @@ -0,0 +1,471 @@ +package vector + +//@Title vector +//@Description +// vector向量容器包 +// 以动态数组的形式实现 +// 该容器可以在尾部实现线性增减元素 +// 通过interface实现泛型 +// 可接纳不同类型的元素 +// 但建议在同一个vector中使用相同类型的元素 +// 可通过配合比较器competitor和迭代器iterator对该vector容器进行排序查找或遍历 + +import ( + "github.com/hlccd/goSTL/utils/comparator" + "github.com/hlccd/goSTL/utils/iterator" + "sync" +) + +//vector向量结构体 +//包含动态数组和该数组的尾下标 +//当删除节点时仅仅需要长度-1即可 +//当剩余长度较小时会采取缩容策略释放空间 +//当添加节点时若未占满全部已分配空间则长度+1同时进行覆盖存放 +//当添加节点时尾指针大于已分配空间长度,则按照扩容策略进行扩容 +//并发控制锁用以保证在高并发过程中不会出现错误 +//使用比较器重载了Sort +type Vector struct { + data []interface{} //动态数组 + len uint64 //当前已用数量 + cap uint64 //可容纳元素数量 + mutex sync.Mutex //并发控制锁 +} + +//vector扩容边界,边界内进行翻倍扩容,边界外进行固定扩容 +const bound = 4294967296 + +//vector向量容器接口 +//存放了vector容器可使用的函数 +//对应函数介绍见下方 +type vectorer interface { + Iterator() (i *Iterator.Iterator) //返回一个包含vector所有元素的迭代器 + Sort(Cmp ...comparator.Comparator) //利用比较器对其进行排序 + Size() (num uint64) //返回vector的长度 + Cap() (num uint64) //返回vector的容量 + Clear() //清空vector + Empty() (b bool) //返回vector是否为空,为空则返回true反之返回false + PushBack(e interface{}) //向vector末尾插入一个元素 + PopBack() //弹出vector末尾元素 + Insert(idx uint64, e interface{}) //向vector第idx的位置插入元素e,同时idx后的其他元素向后退一位 + Erase(idx uint64) //删除vector的第idx个元素 + Reverse() //逆转vector中的数据顺序 + At(idx uint64) (e interface{}) //返回vector的第idx的元素 + Front() (e interface{}) //返回vector的第一个元素 + Back() (e interface{}) //返回vector的最后一个元素 +} + +//@title New +//@description +// 新建一个vector向量容器并返回 +// 初始vector的切片数组为空 +// 初始vector的长度为0,容量为1 +//@receiver nil +//@param nil +//@return v *Vector 新建的vector指针 +func New() (v *Vector) { + return &Vector{ + data: make([]interface{}, 1, 1), + len: 0, + cap: 1, + mutex: sync.Mutex{}, + } +} + +//@title Iterator +//@description +// 以vector向量容器做接收者 +// 释放未使用的空间,并将已使用的部分用于创建迭代器 +// 返回一个包含容器中所有使用元素的迭代器 +//@receiver v *Vector 接受者vector的指针 +//@param nil +//@return i *iterator.Iterator 新建的Iterator迭代器指针 +func (v *Vector) Iterator() (i *Iterator.Iterator) { + if v == nil { + v = New() + } + v.mutex.Lock() + if v.data == nil { + //data不存在,新建一个 + v.data = make([]interface{}, 1, 1) + v.len = 0 + v.cap = 1 + } else if v.len < v.cap { + //释放未使用的空间 + tmp := make([]interface{}, v.len, v.len) + copy(tmp, v.data) + v.data = tmp + } + //创建迭代器 + i = Iterator.New(&v.data) + v.mutex.Unlock() + return i +} + +//@title Sort +//@description +// 以vector向量容器做接收者 +// 将vector向量容器中不使用空间释放掉 +// 对元素中剩余的部分进行排序 +//@receiver v *Vector 接受者vector的指针 +//@param Cmp ...comparator.Comparator 比较函数 +//@return nil +func (v *Vector) Sort(Cmp ...comparator.Comparator) { + if v == nil { + v = New() + } + v.mutex.Lock() + if v.data == nil { + //data不存在,新建一个 + v.data = make([]interface{}, 1, 1) + v.len = 0 + v.cap = 1 + } else if v.len < v.cap { + //释放未使用空间 + tmp := make([]interface{}, v.len, v.len) + copy(tmp, v.data) + v.data = tmp + v.cap = v.len + } + //调用比较器的Sort进行排序 + if len(Cmp) == 0 { + comparator.Sort(&v.data) + } else { + comparator.Sort(&v.data, Cmp[0]) + } + v.mutex.Unlock() +} + +//@title Size +//@description +// 以vector向量容器做接收者 +// 返回该容器当前含有元素的数量 +// 该长度并非实际占用空间数量,而是实际使用空间 +//@receiver v *Vector 接受者vector的指针 +//@param nil +//@return num int 容器中实际使用元素所占空间大小 +func (v *Vector) Size() (num uint64) { + if v == nil { + v = New() + } + return v.len +} + +//@title Cap +//@description +// 以vector向量容器做接收者 +// 返回该容器当前容量 +//@receiver v *Vector 接受者vector的指针 +//@param nil +//@return num int 容器中实际使用元素所占空间大小 +func (v *Vector) Cap() (num uint64) { + if v == nil { + v = New() + } + return v.cap +} + +//@title Clear +//@description +// 以vector向量容器做接收者 +// 将该容器中的动态数组重置,所承载的元素清空 +//@receiver v *Vector 接受者vector的指针 +//@param nil +//@return nil +func (v *Vector) Clear() { + if v == nil { + v = New() + } + v.mutex.Lock() + //清空data + v.data = make([]interface{}, 1, 1) + v.len = 0 + v.cap = 1 + v.mutex.Unlock() +} + +//@title Empty +//@description +// 以vector向量容器做接收者 +// 判断该vector向量容器是否含有元素 +// 如果含有元素则不为空,返回false +// 如果不含有元素则说明为空,返回true +// 该判断过程通过长度进行判断 +// 当长度为0时说明不含有元素 +// 当长度大于0时说明含有元素 +//@receiver v *Vector 接受者vector的指针 +//@param nil +//@return b bool 该容器是空的吗? +func (v *Vector) Empty() (b bool) { + if v == nil { + v = New() + } + return v.Size() <= 0 +} + +//@title PushBack +//@description +// 以vector向量容器做接收者 +// 在容器尾部插入元素 +// 若长度小于容量时,则对以长度为下标的位置进行覆盖,同时len++ +// 若长度等于容量时,需要进行扩容 +// 对于扩容而言,当容量小于bound时,直接将容量翻倍,否则将容量增加bound +//@receiver v *Vector 接受者vector的指针 +//@param e interface{} 待插入元素 +//@return nil +func (v *Vector) PushBack(e interface{}) { + if v == nil { + v = New() + } + v.mutex.Lock() + if v.len < v.cap { + //还有冗余,直接添加 + v.data[v.len] = e + } else { + //冗余不足,需要扩容 + if v.cap <= bound { + //容量翻倍 + if v.cap == 0 { + v.cap = 1 + } + v.cap *= 2 + } else { + //容量增加bound + v.cap += bound + } + //复制扩容前的元素 + tmp := make([]interface{}, v.cap, v.cap) + copy(tmp, v.data) + v.data = tmp + v.data[v.len] = e + } + v.len++ + v.mutex.Unlock() +} + +//@title PopBack +//@description +// 以vector向量容器做接收者 +// 弹出容器最后一个元素,同时长度--即可 +// 若容器为空,则不进行弹出 +// 当弹出元素后,可能进行缩容 +// 当容量和实际使用差值超过bound时,容量直接减去bound +// 否则,当实际使用长度是容量的一半时,进行折半缩容 +//@receiver v *Vector 接受者vector的指针 +//@param nil +//@return nil +func (v *Vector) PopBack() { + if v == nil { + v = New() + } + if v.Empty() { + return + } + v.mutex.Lock() + v.len-- + if v.cap-v.len >= bound { + //容量和实际使用差值超过bound时,容量直接减去bound + v.cap -= bound + tmp := make([]interface{}, v.cap, v.cap) + copy(tmp, v.data) + v.data = tmp + } else if v.len*2 < v.cap { + //实际使用长度是容量的一半时,进行折半缩容 + v.cap /= 2 + tmp := make([]interface{}, v.cap, v.cap) + copy(tmp, v.data) + v.data = tmp + } + v.mutex.Unlock() +} + +//@title Insert +//@description +// 以vector向量容器做接收者 +// 向容器切片中插入一个元素 +// 当idx不大于0时,则在容器切片的头部插入元素 +// 当idx不小于切片使用长度时,在容器末尾插入元素 +// 否则在切片中间第idx位插入元素,同时后移第idx位以后的元素 +// 根据冗余量选择是否扩容,扩容策略同上 +// 插入后len++ +//@receiver v *Vector 接受者vector的指针 +//@param idx uint64 待插入节点的位置(下标从0开始) +//@param e interface{} 待插入元素 +//@return nil +func (v *Vector) Insert(idx uint64, e interface{}) { + if v == nil { + v = New() + } + v.mutex.Lock() + var tmp []interface{} + if v.len >= v.cap { + //冗余不足,进行扩容 + if v.cap <= bound { + //容量翻倍 + if v.cap == 0 { + v.cap = 1 + } + v.cap *= 2 + } else { + //容量增加bound + v.cap += bound + } + //复制扩容前的元素 + tmp = make([]interface{}, v.cap, v.cap) + copy(tmp, v.data) + v.data = tmp + } + //从后往前复制,即将idx后的全部后移一位即可 + var p uint64 + for p = v.len; p > 0 && p > uint64(idx); p-- { + v.data[p] = v.data[p-1] + } + v.data[p] = e + v.len++ + v.mutex.Unlock() +} + +//@title Erase +//@description +// 以vector向量容器做接收者 +// 向容器切片中删除一个元素 +// 当idx不大于0时,则删除头部 +// 当idx不小于切片使用长度时,则删除尾部 +// 否则在切片中间第idx位删除元素,同时前移第idx位以后的元素 +// 长度同步-- +// 进行缩容判断,缩容策略同上 +//@receiver v *Vector 接受者vector的指针 +//@param idx uint64 待删除节点的位置(下标从0开始) +//@return nil +func (v *Vector) Erase(idx uint64) { + if v == nil { + v = New() + } + if v.Empty() { + return + } + v.mutex.Lock() + for p := idx; p < v.len-1; p++ { + v.data[p] = v.data[p+1] + } + v.len-- + if v.cap-v.len >= bound { + //容量和实际使用差值超过bound时,容量直接减去bound + v.cap -= bound + tmp := make([]interface{}, v.cap, v.cap) + copy(tmp, v.data) + v.data = tmp + } else if v.len*2 < v.cap { + //实际使用长度是容量的一半时,进行折半缩容 + v.cap /= 2 + tmp := make([]interface{}, v.cap, v.cap) + copy(tmp, v.data) + v.data = tmp + } + v.mutex.Unlock() +} + +//@title Reverse +//@description +// 以vector向量容器做接收者 +// 将vector容器中不使用空间释放掉 +// 将该容器中的泛型切片中的所有元素顺序逆转 +//@receiver v *Vector 接受者vector的指针 +//@param nil +//@return nil +func (v *Vector) Reverse() { + if v == nil { + v = New() + } + v.mutex.Lock() + if v.data == nil { + //data不存在,新建一个 + v.data = make([]interface{}, 1, 1) + v.len = 0 + v.cap = 1 + } else if v.len < v.cap { + //释放未使用的空间 + tmp := make([]interface{}, v.len, v.len) + copy(tmp, v.data) + v.data = tmp + v.cap = v.len + } + for i := uint64(0); i < v.len/2; i++ { + v.data[i], v.data[v.len-i-1] = v.data[v.len-i-1], v.data[i] + } + v.mutex.Unlock() +} + +//@title At +//@description +// 以vector向量容器做接收者 +// 根据传入的idx寻找位于第idx位的元素 +// 当idx不在容器中泛型切片的使用范围内 +// 即当idx小于0或者idx大于容器所含有的元素个数时返回nil +// 反之返回对应位置的元素 +//@receiver v *Vector 接受者vector的指针 +//@param idx uint64 待查找元素的位置(下标从0开始) +//@return e interface{} 从容器中查找的第idx位元素 +func (v *Vector) At(idx uint64) (e interface{}) { + if v == nil { + v = New() + return nil + } + v.mutex.Lock() + if idx < 0 && idx >= v.Size() { + v.mutex.Unlock() + return nil + } + if v.Size() > 0 { + e = v.data[idx] + v.mutex.Unlock() + return e + } + v.mutex.Unlock() + return nil +} + +//@title Front +//@description +// 以vector向量容器做接收者 +// 返回该容器的第一个元素 +// 若该容器当前为空,则返回nil +//@receiver v *Vector 接受者vector的指针 +//@param nil +//@return e interface{} 容器的第一个元素 +func (v *Vector) Front() (e interface{}) { + if v == nil { + v = New() + return nil + } + v.mutex.Lock() + if v.Size() > 0 { + e = v.data[0] + v.mutex.Unlock() + return e + } + v.mutex.Unlock() + return nil +} + +//@title Back +//@description +// 以vector向量容器做接收者 +// 返回该容器的最后一个元素 +// 若该容器当前为空,则返回nil +//@receiver v *Vector 接受者vector的指针 +//@param nil +//@return e interface{} 容器的最后一个元素 +func (v *Vector) Back() (e interface{}) { + if v == nil { + v = New() + return nil + } + v.mutex.Lock() + if v.Size() > 0 { + e = v.data[v.len-1] + v.mutex.Unlock() + return e + } + v.mutex.Unlock() + return nil +} diff --git a/utils/comparator/bound.go b/utils/comparator/bound.go new file mode 100644 index 0000000..6336693 --- /dev/null +++ b/utils/comparator/bound.go @@ -0,0 +1,116 @@ +package comparator + +//@Title comparator +//@Description +// 可查找有序序列中某一元素的上界和下届 +// 当该元素存在时,上界和下届返回的下标位置指向该元素 +// 当该元素不存在时,上界和下届指向下标错位且指向位置并非该元素 + +//@title UpperBound +//@description +// 通过传入的比较函数对待查找数组进行查找以获取待查找元素的上界即不大于它的最大值的下标 +// 以传入的比较函数进行比较 +// 如果该元素存在,则上界指向元素为该元素 +// 如果该元素不存在,上界指向元素为该元素的前一个元素 +//@receiver nil +//@param arr *[]interface{} 待查找数组 +//@param e interface{} 待查找元素 +//@param Cmp ...Comparator 比较函数 +//@return idx int 待查找元素的上界 +func UpperBound(arr *[]interface{}, e interface{}, Cmp ...Comparator) (idx int) { + if arr==nil || (*arr)==nil || len((*arr)) == 0 { + return -1 + } + //判断比较函数是否有效 + var cmp Comparator + cmp = nil + if len(Cmp) == 0 { + cmp = GetCmp(e) + } else { + cmp = Cmp[0] + } + if cmp == nil { + return -1 + } + //寻找该元素的上界 + return upperBound(arr, e, cmp) +} + +//@title upperBound +//@description +// 通过传入的比较函数对待查找数组进行查找以获取待查找元素的上界即不大于它的最大值的下标 +// 以传入的比较函数进行比较 +// 如果该元素存在,则上界指向元素为该元素,且为最右侧 +// 如果该元素不存在,上界指向元素为该元素的前一个元素 +// 以二分查找的方式寻找该元素的上界 +//@receiver nil +//@param arr *[]interface{} 待查找数组 +//@param e interface{} 待查找元素 +//@param Cmp ...Comparator 比较函数 +//@return idx int 待查找元素的上界 +func upperBound(arr *[]interface{}, e interface{}, cmp Comparator) (idx int) { + l, m, r := 0, len((*arr)) / 2, len((*arr))-1 + for l < r { + m = (l + r + 1) / 2 + if cmp((*arr)[m], e) <= 0 { + l = m + } else { + r = m - 1 + } + } + return l +} + +//@title LowerBound +//@description +// 通过传入的比较函数对待查找数组进行查找以获取待查找元素的下界即不小于它的最小值的下标 +// 以传入的比较函数进行比较 +// 如果该元素存在,则上界指向元素为该元素 +// 如果该元素不存在,上界指向元素为该元素的后一个元素 +//@receiver nil +//@param arr *[]interface{} 待查找数组 +//@param e interface{} 待查找元素 +//@param Cmp ...Comparator 比较函数 +//@return idx int 待查找元素的下界 +func LowerBound(arr *[]interface{}, e interface{}, Cmp ...Comparator) (idx int) { + if arr==nil || (*arr)==nil || len((*arr)) == 0 { + return -1 + } + //判断比较函数是否有效 + var cmp Comparator + cmp = nil + if len(Cmp) == 0 { + cmp = GetCmp(e) + } else { + cmp = Cmp[0] + } + if cmp == nil { + return -1 + } + //寻找该元素的下界 + return lowerBound(arr, e, cmp) +} + +//@title lowerBound +//@description +// 通过传入的比较函数对待查找数组进行查找以获取待查找元素的下界即不小于它的最小值的下标 +// 以传入的比较函数进行比较 +// 如果该元素存在,则上界指向元素为该元素,且为最右侧 +// 如果该元素不存在,上界指向元素为该元素的后一个元素 +//@receiver nil +//@param arr *[]interface{} 待查找数组 +//@param e interface{} 待查找元素 +//@param Cmp ...Comparator 比较函数 +//@return idx int 待查找元素的下界 +func lowerBound(arr *[]interface{}, e interface{}, cmp Comparator) (idx int) { + l, m, r := 0, len((*arr)) / 2, len((*arr)) + for l < r { + m = (l + r) / 2 + if cmp((*arr)[m], e) >= 0 { + r = m + } else { + l = m + 1 + } + } + return l +} diff --git a/utils/comparator/comparator.go b/utils/comparator/comparator.go new file mode 100644 index 0000000..3b12a3d --- /dev/null +++ b/utils/comparator/comparator.go @@ -0,0 +1,278 @@ +package comparator + +//@Title comparator +//@Description +// 比较器 +// 定义了一个比较器类型,该类型可传入两个泛型并返回一个整数判断大小 +// 该比较器用于定义的数据结构中传入数据之间的比较 +// 该包内定义了一些自带类型的比较类型 +// 当使用自定义的数据结构时若不进行比较器的传入则使用默认比较器 +// 若传入类型非系统自带类型,则返回空比较器同时对数据的传入失败 + +// 比较器将会返回数字num +// num > 0 ,if a > b +// num = 0 ,if a = b +// num < 0 ,if a < b + +type Comparator func(a, b interface{}) int + +//比较器的特种——相等器 +//判断传入的两个元素是否相等 +type Equaler func(a, b interface{}) (B bool) + +//@title GetCmp +//@description +// 传入一个数据并根据该数据类型返回一个对应的比较器 +// 若该类型并非系统自带类型,则返回个空比较器 +// 若传入元素为nil则之间返回nil +//@receiver nil +//@param e interface{} +//@return cmp Comparator 该类型对应的默认比较器 +func GetCmp(e interface{}) (cmp Comparator) { + if e == nil { + return nil + } + switch e.(type) { + case bool: + return boolCmp + case int: + return intCmp + case int8: + return int8Cmp + case uint8: + return uint8Cmp + case int16: + return int16Cmp + case uint16: + return uint16Cmp + case int32: + return int32Cmp + case uint32: + return uint32Cmp + case int64: + return int64Cmp + case uint64: + return uint64Cmp + case float32: + return float32Cmp + case float64: + return float64Cmp + case complex64: + return complex64Cmp + case complex128: + return complex128Cmp + case string: + return stringCmp + } + return nil +} + +//@title GetEqual +//@description +// 传入一个数据并根据该数据类型返回一个对应的比较器 +// 若该类型并非系统自带类型,则返回个空比较器 +// 若传入元素为nil则之间返回nil +//@receiver nil +//@param e interface{} +//@return cmp Comparator 该类型对应的默认比较器 +func GetEqual() (equ Equaler) { + return basicEqual +} + +//@title basicEqual +//@description +// 返回基本比较器 +// 即有且仅有判断量元素是否完全相等 +//@receiver a interface{} 待判断相等的第一个元素 +//@receiver b interface{} 待判断相等的第二个元素 +//@param nil +//@return B bool 这两个元素是否相等? +func basicEqual(a, b interface{}) (B bool) { + return a == b +} + +//以下为系统自带类型的默认比较器 + +func boolCmp(a, b interface{}) int { + if a == b { + return 0 + } + if a.(bool) { + return 1 + } else if b.(bool) { + return -1 + } + return 0 +} +func intCmp(a, b interface{}) int { + if a == b { + return 0 + } + if a.(int) > b.(int) { + return 1 + } else if a.(int) < b.(int) { + return -1 + } + return 0 +} +func int8Cmp(a, b interface{}) int { + if a == b { + return 0 + } + if a.(int8) > b.(int8) { + return 1 + } else if a.(int8) < b.(int8) { + return -1 + } + return 0 +} +func uint8Cmp(a, b interface{}) int { + if a == b { + return 0 + } + if a.(uint8) > b.(uint8) { + return 1 + } else if a.(uint8) < b.(uint8) { + return -1 + } + return 0 +} +func int16Cmp(a, b interface{}) int { + if a == b { + return 0 + } + if a.(int16) > b.(int16) { + return 1 + } else if a.(int16) < b.(int16) { + return -1 + } + return 0 +} +func uint16Cmp(a, b interface{}) int { + if a == b { + return 0 + } + if a.(uint16) > b.(uint16) { + return 1 + } else if a.(uint16) < b.(uint16) { + return -1 + } + return 0 +} +func int32Cmp(a, b interface{}) int { + if a == b { + return 0 + } + if a.(int32) > b.(int32) { + return 1 + } else if a.(int32) < b.(int32) { + return -1 + } + return 0 +} +func uint32Cmp(a, b interface{}) int { + if a == b { + return 0 + } + if a.(uint32) > b.(uint32) { + return 1 + } else if a.(uint32) < b.(uint32) { + return -1 + } + return 0 +} +func int64Cmp(a, b interface{}) int { + if a == b { + return 0 + } + if a.(int64) > b.(int64) { + return 1 + } else if a.(int64) < b.(int64) { + return -1 + } + return 0 +} +func uint64Cmp(a, b interface{}) int { + if a == b { + return 0 + } + if a.(uint64) > b.(uint64) { + return 1 + } else if a.(uint64) < b.(uint64) { + return -1 + } + return 0 +} +func float32Cmp(a, b interface{}) int { + if a == b { + return 0 + } + if a.(float32) > b.(float32) { + return 1 + } else if a.(float32) < b.(float32) { + return -1 + } + return 0 +} +func float64Cmp(a, b interface{}) int { + if a == b { + return 0 + } + if a.(float64) > b.(float64) { + return 1 + } else if a.(float64) < b.(float64) { + return -1 + } + return 0 +} +func complex64Cmp(a, b interface{}) int { + if a == b { + return 0 + } + if real(a.(complex64)) > real(b.(complex64)) { + return 1 + } else if real(a.(complex64)) < real(b.(complex64)) { + return -1 + } else { + if imag(a.(complex64)) > imag(b.(complex64)) { + return 1 + } else if imag(a.(complex64)) < imag(b.(complex64)) { + return -1 + } + } + return 0 +} +func complex128Cmp(a, b interface{}) int { + if a == b { + return 0 + } + if real(a.(complex128)) > real(b.(complex128)) { + return 1 + } else if real(a.(complex128)) < real(b.(complex128)) { + return -1 + } else { + if imag(a.(complex128)) > imag(b.(complex128)) { + return 1 + } else if imag(a.(complex128)) < imag(b.(complex128)) { + return -1 + } + } + return 0 +} +func stringCmp(a, b interface{}) int { + if a == b { + return 0 + } + if len(a.(string)) > len(b.(string)) { + return 1 + } else if len(a.(string)) < len(b.(string)) { + return -1 + } else { + if a.(string) > b.(string) { + return 1 + } else if a.(string) < b.(string) { + return -1 + } + } + return 0 +} diff --git a/utils/comparator/nth_element.go b/utils/comparator/nth_element.go new file mode 100644 index 0000000..4934cf6 --- /dev/null +++ b/utils/comparator/nth_element.go @@ -0,0 +1,79 @@ +package comparator + +//@Title comparator +//@Description +// 该包内通过利用比较函数重排传入的数组,使得下标为n的元素必然是第n+1大的(考虑到下标从0开始) +// 对二分排序的变形,当只对该节点位置存在的某一局部进行查找即可 + +//@title NthElement +//@description +// 若数组指针为nil或者数组为nil或数组长度为0则直接结束即可 +// 通过利用比较函数重排传入的数组,使得下标为n的元素必然是第n+1大的(考虑到下标从0开始) +// 若n大于数组长度,直接结束,否则对第n+1大的元素排序后返回该元素 +//@receiver nil +//@param begin *[]interface{} 待查找的元素数组指针 +//@param n int 待查找的是第n位,从0计数 +//@param Cmp ...Comparator 比较函数 +//@return value interface{} 第n+1大的元素 +func NthElement(arr *[]interface{}, n int, Cmp ...Comparator) (value interface{}){ + if arr==nil || (*arr)==nil || len((*arr)) == 0 { + return nil + } + //判断比较函数是否有效 + var cmp Comparator + cmp = nil + if len(Cmp) > 0 { + cmp = Cmp[0] + } else { + cmp = GetCmp((*arr)[0]) + } + if cmp == nil { + return nil + } + //判断待确认的第n位是否在该集合范围内 + if len((*arr)) < n || n<0 { + return nil + } + //进行查找 + nthElement(arr,0,len((*arr))-1, n, cmp) + return (*arr)[n] +} + +//@title nthElement +//@description +// 对传入的开启和结尾的两个比较器中的值进行查找 +// 以传入的比较器进行比较 +// 通过局部二分的方式进行查找并将第n小的元素放到第n位置(大小按比较器进行确认,默认未小) +//@receiver nil +//@param begin *[]interface{} 待查找的元素数组指针 +//@param l int 查找范围的左下标 +//@param r int 查找范围的右下标 +//@param n int 待查找的是第n位,从0计数 +//@param Cmp ...Comparator 比较函数 +func nthElement(arr *[]interface{},l,r int, n int, cmp Comparator){ + //二分该区域并对此进行预排序 + if l >= r { + return + } + m := (*arr)[(r + l) / 2] + i, j := l-1, r+1 + for i < j { + i++ + for cmp((*arr)[i], m) < 0 { + i++ + } + j-- + for cmp((*arr)[j], m) > 0 { + j-- + } + if i < j { + (*arr)[i],(*arr)[j]=(*arr)[j],(*arr)[i] + } + } + //确认第n位的范围进行局部二分 + if n-1 >= i { + nthElement(arr,j+1,r, n, cmp) + } else { + nthElement(arr,l,j, n, cmp) + } +} diff --git a/utils/comparator/search.go b/utils/comparator/search.go new file mode 100644 index 0000000..fa50f12 --- /dev/null +++ b/utils/comparator/search.go @@ -0,0 +1,68 @@ +package comparator + +//@Title comparator +//@Description +// 该部分为对带查找数组中元素进行二分查找 +// warning:仅对有序元素集合有效 + +//@title Search +//@description +// 若数组指针为nil或者数组为nil或数组长度为0则直接结束即可 +// 通过比较函数对传入的数组中的元素集合进行二分查找 +// 若并未传入比较函数则寻找默认比较函数 +// 找到后返回该元素的下标 +// 若该元素不在该部分内存在,则返回-1 +//@receiver nil +//@param arr *[]interface{} 待查找的有序数组 +//@param e interface{} 待查找元素 +//@param Cmp ...Comparator 比较函数 +//@return idx int 待查找元素下标 +func Search(arr *[]interface{}, e interface{}, Cmp ...Comparator) (idx int) { + if arr==nil || (*arr)==nil || len((*arr)) == 0 { + return + } + //判断比较函数是否有效,若无效则寻找默认比较函数 + var cmp Comparator + cmp = nil + if len(Cmp) == 0 { + cmp = GetCmp(e) + } else { + cmp = Cmp[0] + } + if cmp == nil { + //若并非默认类型且未传入比较器则直接结束 + return -1 + } + //查找开始 + return search(arr, e, cmp) +} + +//@title search +//@description +// 通过比较函数对传入的数组中的元素集合进行二分查找 +// 找到后返回该元素的下标 +// 若该元素不在该部分内存在,则返回-1 +//@receiver nil +//@param arr *[]interface{} 待查找的有序数组 +//@param e interface{} 待查找元素 +//@param Cmp ...Comparator 比较函数 +//@return idx int 待查找元素下标 +func search(arr *[]interface{}, e interface{}, cmp Comparator) (idx int) { + //通过二分查找的方式寻找该元素 + l, m, r := 0, (len((*arr))-1)/2, len((*arr)) + for l < r { + m = (l + r) / 2 + if cmp((*arr)[m], e) < 0 { + l = m + 1 + } else { + r = m + } + } + //查找结束 + if (*arr)[l] == e { + //该元素存在,返回下标 + return l + } + //该元素不存在,返回-1 + return -1 +} diff --git a/utils/comparator/sort.go b/utils/comparator/sort.go new file mode 100644 index 0000000..bcfaa86 --- /dev/null +++ b/utils/comparator/sort.go @@ -0,0 +1,123 @@ +package comparator + +//@Title comparator +//@Description +// 该包内通过待比较数组和比较函数进行排序 +// 当前支持二分排序和归并排序 + + +//@title Sort +//@description +// 若数组指针为nil或者数组为nil或数组长度为0则直接结束即可 +// 对传入的数组进行通过比较函数进行比较 +// 若未传入比较函数则寻找默认比较器,默认比较器排序结果为升序 +// 若该泛型类型并非系统默认类型之一,则不进行排序 +// 当待排序元素个数超过2^16个时使用归并排序 +// 当待排序元素个数少于2^16个时使用二分排序 +//@receiver nil +//@param arr *[]interface{} 待排序数组的指针 +//@param Cmp ...Comparator 比较函数 +//@return nil +func Sort(arr *[]interface{}, Cmp ...Comparator) { + //如果传入一个空数组或nil,则直接结束 + if arr==nil || (*arr)==nil || len((*arr)) == 0 { + return + } + var cmp Comparator + cmp = nil + if len(Cmp) > 0 { + cmp = Cmp[0] + } else { + cmp = GetCmp((*arr)[0]) + } + if cmp == nil { + //未传入比较器且并非默认类型导致未找到默认比较器则直接终止排序 + return + } + //根据数组长度进行分类选择排序函数 + if len((*arr)) < 2^26 { + //当长度小于2^16时使用二分排序 + binary(arr,0,len((*arr))-1, cmp) + } else { + merge(arr,0,len((*arr))-1, cmp) + } +} + +//@title binary +//@description +// 二分排序 +// 对传入的待比较数组中的元素使用比较函数进行二分排序 +//@receiver nil +//@param arr *[]interface{} 待排序数组指针 +//@param l int 待排序数组的左下标 +//@param r int 待排序数组的右下标 +//@param cmp Comparator 比较函数 +//@return nil +func binary(arr *[]interface{},l,r int, cmp Comparator) { + //对当前部分进行预排序,使得两侧都大于或小于中间值 + if l >= r { + return + } + m := (*arr)[(r + l) / 2] + i, j := l-1, r+1 + for i < j { + i++ + for cmp((*arr)[i], m) < 0 { + i++ + } + j-- + for cmp((*arr)[j],m) > 0 { + j-- + } + if i < j { + (*arr)[i],(*arr)[j]=(*arr)[j],(*arr)[i] + } + } + //对分好的两侧进行迭代二分排序 + binary(arr,l,j, cmp) + binary(arr,j+1,r, cmp) +} + +//@title merge +//@description +// 归并排序 +// 对传入的两个迭代器中的内容使用比较器进行归并排序 +//@receiver nil +//@param arr *[]interface{} 待排序数组指针 +//@param l int 待排序数组的左下标 +//@param r int 待排序数组的右下标 +//@param cmp Comparator 比较函数 +//@return nil +func merge(arr *[]interface{},l,r int, cmp Comparator) { + //对当前部分进行分组排序,将该部分近似平均的拆为两部分进行比较排序 + if l >= r { + return + } + m := (r + l) / 2 + //对待排序内容进行二分 + merge(arr,l,m, cmp) + merge(arr,m+1,r, cmp) + //二分结束后依次比较进行归并 + i, j := l, m+1 + var tmp []interface{}=make([]interface{},0,r-l+1) + for i <= m && j <= r { + if cmp((*arr)[i], (*arr)[j]) <= 0 { + tmp = append(tmp, (*arr)[i]) + i++ + } else { + tmp = append(tmp, (*arr)[j]) + j++ + } + } + //当一方比较到头时将另一方剩余内容全部加入进去 + for ; i <= m; i++ { + tmp = append(tmp, (*arr)[i]) + } + for ; j <= r; j++ { + tmp = append(tmp, (*arr)[j]) + } + //将局部排序结果放入迭代器中 + for i, j = l, 0; i <= r; i, j = i+1, j+1 { + (*arr)[i]=tmp[j] + } +} \ No newline at end of file diff --git a/utils/iterator/Iterator.go b/utils/iterator/Iterator.go new file mode 100644 index 0000000..d3c489c --- /dev/null +++ b/utils/iterator/Iterator.go @@ -0,0 +1,305 @@ +package Iterator + +//@Title Iterator +//@Description +// 迭代器 +// 定义了一套迭代器接口和迭代器类型 +// 本套接口定义了迭代器所要执行的基本函数 +// 数据结构在使用迭代器时需要重写函数 +// 其中主要包括:生成迭代器,移动迭代器,判断是否可移动 + +//Iterator迭代器 +//包含泛型切片和该迭代器当前指向元素的下标 +//可通过下标和泛型切片长度来判断是否可以前移或后移 +//当index不小于0时迭代器可前移 +//当index小于data的长度时可后移 +type Iterator struct { + data *[]interface{} //该迭代器中存放的元素集合的指针 + index int //该迭代器当前指向的元素下标,-1即不存在元素 +} + +//Iterator迭代器接口 +//定义了一套迭代器接口函数 +//函数含义详情见下列描述 +type Iteratorer interface { + Begin() (I *Iterator) //将该迭代器设为位于首节点并返回新迭代器 + End() (I *Iterator) //将该迭代器设为位于尾节点并返回新迭代器 + Get(idx int) (I *Iterator) //将该迭代器设为位于第idx节点并返回该迭代器 + Value() (e interface{}) //返回该迭代器下标所指元素 + HasNext() (b bool) //判断该迭代器是否可以后移 + Next() (b bool) //将该迭代器后移一位 + HasPre() (b bool) //判罚该迭代器是否可以前移 + Pre() (b bool) //将该迭代器前移一位 +} + +//@title New +//@description +// 新建一个Iterator迭代器容器并返回 +// 传入的切片指针设为迭代器所承载的元素集合 +// 若传入下标,则将传入的第一个下标设为该迭代器当前指向下标 +// 若该下标超过元素集合范围,则寻找最近的下标 +// 若元素集合为空,则下标设为-1 +//@receiver nil +//@param data *[]interface{} 迭代器所承载的元素集合的指针 +//@param Idx ...int 预设的迭代器的下标 +//@return i *Iterator 新建的Iterator迭代器指针 +func New(data *[]interface{}, Idx ...int) (i *Iterator) { + //迭代器下标 + var idx int + if len(Idx) <= 0 { + //没有传入下标,则将下标设为0 + idx = 0 + } else { + //有传入下标,则将传入下标第一个设为迭代器下标 + idx = Idx[0] + } + if len((*data)) > 0 { + //如果元素集合非空,则判断下标是否超过元素集合范围 + if idx >= len((*data)) { + //如果传入下标超过元素集合范围则寻找最近的下标值 + idx = len((*data)) - 1 + } + } else { + //如果元素集合为空则将下标设为-1 + idx = -1 + } + //新建并返回迭代器 + return &Iterator{ + data: data, + index: idx, + } +} + +//@title Begin +//@description +// 以Iterator迭代器指针做接收者 +// 如果迭代器为空,直接结束 +// 如果该迭代器元素集合为空,则将下标设为-1 +// 如果该迭代器元素集合不为空,则将下标设为0 +// 随后返回新迭代器指针 +//@receiver i *Iterator 迭代器指针 +//@param nil +//@return I *Iterator 修改后的新迭代器指针 +func (i *Iterator) Begin() (I *Iterator) { + if i == nil { + //迭代器为空,直接结束 + return nil + } + if len((*i.data)) == 0 { + //迭代器元素集合为空,下标设为-1 + i.index = -1 + } else { + //迭代器元素集合非空,下标设为0 + i.index = 0 + } + //返回修改后的新指针 + return &Iterator{ + data: i.data, + index: i.index, + } +} + +//@title End +//@description +// 以Iterator迭代器指针做接收者 +// 如果迭代器为空,直接结束 +// 如果该迭代器元素集合为空,则将下标设为-1 +// 如果该迭代器元素集合不为空,则将下标设为元素集合的最后一个元素的下标 +// 随后返回新迭代器指针 +//@receiver i *Iterator 迭代器指针 +//@param nil +//@return I *Iterator 修改后的新迭代器指针 +func (i *Iterator) End() (I *Iterator) { + if i == nil { + //迭代器为空,直接返回 + return nil + } + if len((*i.data)) == 0 { + //元素集合为空,下标设为-1 + i.index = -1 + } else { + //元素集合非空,下标设为最后一个元素的下标 + i.index = len((*i.data)) - 1 + } + //返回修改后的该指针 + return &Iterator{ + data: i.data, + index: i.index, + } +} + +//@title Get +//@description +// 以Iterator迭代器指针做接收者 +// 如果迭代器为空,直接结束 +// 如果该迭代器元素集合为空,则将下标设为-1 +// 如果该迭代器元素集合不为空,则将下标设为传入的预设下标 +// 如果预设下标超过元素集合范围,则将下标设为最近元素的下标 +// 随后返回该迭代器指针 +//@receiver i *Iterator 迭代器指针 +//@param idx int 预设下标 +//@return I *Iterator 修改后的该迭代器指针 +func (i *Iterator) Get(idx int) (I *Iterator) { + if i == nil { + //迭代器为空,直接返回 + return nil + } + if idx <= 0 { + //预设下标超过元素集合范围,将下标设为最近元素的下标,此状态下为首元素下标 + idx = 0 + } else if idx >= len((*i.data))-1 { + //预设下标超过元素集合范围,将下标设为最近元素的下标,此状态下为尾元素下标 + idx = len((*i.data)) - 1 + } + if len((*i.data)) > 0 { + //元素集合非空,迭代器下标设为预设下标 + i.index = idx + } else { + //元素集合为空,迭代器下标设为-1 + i.index = -1 + } + //返回修改后的迭代器指针 + return i +} + +//@title Value +//@description +// 以Iterator迭代器指针做接收者 +// 返回迭代器当前下标所指元素 +// 若迭代器为nil或元素集合为空,返回nil +// 否则返回迭代器当前下标所指向的元素 +// 如果该下标超过元素集合范围,则返回距离最近的元素 +//@receiver i *Iterator 迭代器指针 +//@param nil +//@return e interface{} 迭代器下标所指元素 +func (i *Iterator) Value() (e interface{}) { + if i == nil { + //迭代器为nil,返回nil + return nil + } + if len((*i.data)) == 0 { + //元素集合为空,返回nil + return nil + } + if i.index <= 0 { + //下标超过元素集合范围下限,最近元素为首元素 + i.index = 0 + } + if i.index >= len((*i.data)) { + //下标超过元素集合范围上限,最近元素为尾元素 + i.index = len((*i.data)) - 1 + } + //返回下标指向元素 + return (*i.data)[i.index] +} + +//@title HasNext +//@description +// 以Iterator迭代器指针做接收者 +// 判断该迭代器是否可以后移 +// 当迭代器为nil时不能后移 +// 当元素集合为空时不能后移 +// 当下标到达元素集合范围上限时不能后移 +// 否则可以后移 +//@author hlccd 2021-07-1 +//@receiver i *Iterator 迭代器指针 +//@param nil +//@return b bool 迭代器下标可以后移? +func (i *Iterator) HasNext() (b bool) { + if i == nil { + //迭代器为nil时不能后移 + return false + } + if len((*i.data)) == 0 { + //元素集合为空时不能后移 + return false + } + //下标到达元素集合上限时不能后移,否则可以后移 + return i.index < len((*i.data)) +} + +//@title Next +//@description +// 以Iterator迭代器指针做接收者 +// 将迭代器下标后移 +// 当满足后移条件时进行后移同时返回true +// 当不满足后移条件时将下标设为尾元素下标同时返回false +// 当迭代器为nil时返回false +// 当元素集合为空时下标设为-1同时返回false +//@receiver i *Iterator 迭代器指针 +//@param nil +//@return b bool 迭代器下标后移成功? +func (i *Iterator) Next() (b bool) { + if i == nil { + //迭代器为nil时返回false + return false + } + if i.HasNext() { + //满足后移条件时进行后移 + i.index++ + return true + } + if len((*i.data)) == 0 { + //元素集合为空时下标设为-1同时返回false + i.index = -1 + return false + } + //不满足后移条件时将下标设为尾元素下标并返回false + i.index = len((*i.data)) - 1 + return false +} + +//@title HasPre +//@description +// 以Iterator迭代器指针做接收者 +// 判断该迭代器是否可以前移 +// 当迭代器为nil时不能前移 +// 当元素集合为空时不能前移 +// 当下标到达元素集合范围下限时不能前移 +// 否则可以前移 +//@receiver i *Iterator 迭代器指针 +//@param nil +//@return b bool 迭代器下标可以前移? +func (i *Iterator) HasPre() (b bool) { + if i == nil { + //迭代器为nil时不能前移 + return false + } + if len((*i.data)) == 0 { + //元素集合为空时不能前移 + return false + } + //下标到达元素集合范围下限时不能前移,否则可以后移 + return i.index >= 0 +} + +//@title Pre +//@description +// 以Iterator迭代器指针做接收者 +// 将迭代器下标前移 +// 当满足前移条件时进行前移同时返回true +// 当不满足前移条件时将下标设为首元素下标同时返回false +// 当迭代器为nil时返回false +// 当元素集合为空时下标设为-1同时返回false +//@receiver i *Iterator 迭代器指针 +//@param nil +//@return b bool 迭代器下标前移成功? +func (i *Iterator) Pre() (b bool) { + if i == nil { + //迭代器为nil时返回false + return false + } + if i.HasPre() { + //满足后移条件时进行前移 + i.index-- + return true + } + if len((*i.data)) == 0 { + //元素集合为空时下标设为-1同时返回false + i.index = -1 + return false + } + //不满足后移条件时将下标设为尾元素下标并返回false + i.index = 0 + return false +}