diff --git a/goSTL/algorithm/hash.go b/goSTL/algorithm/hash.go index 793fb46..87a7742 100644 --- a/goSTL/algorithm/hash.go +++ b/goSTL/algorithm/hash.go @@ -1,5 +1,13 @@ 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) { @@ -47,37 +55,37 @@ func boolHash(key interface{}) uint64 { return 0 } func intHash(key interface{}) uint64 { - return uint64(key.(int) * key.(int)/2) + return uint64(key.(int) * key.(int) / 2) } func int8Hash(key interface{}) uint64 { - return uint64(key.(int8) * key.(int8)/2) + return uint64(key.(int8) * key.(int8) / 2) } func uint8Hash(key interface{}) uint64 { - return uint64(key.(uint8) * key.(uint8)/2) + return uint64(key.(uint8) * key.(uint8) / 2) } func int16Hash(key interface{}) uint64 { - return uint64(key.(int16) * key.(int16)/2) + return uint64(key.(int16) * key.(int16) / 2) } func uint16Hash(key interface{}) uint64 { - return uint64(key.(uint16) * key.(uint16)/2) + return uint64(key.(uint16) * key.(uint16) / 2) } func int32Hash(key interface{}) uint64 { - return uint64(key.(int32) * key.(int32)/2) + return uint64(key.(int32) * key.(int32) / 2) } func uint32Hash(key interface{}) uint64 { - return uint64(key.(uint32) * key.(uint32)/2) + return uint64(key.(uint32) * key.(uint32) / 2) } func int64Hash(key interface{}) uint64 { - return uint64(key.(int64) * key.(int64)/2) + return uint64(key.(int64) * key.(int64) / 2) } func uint64Hash(key interface{}) uint64 { - return uint64(key.(uint64) * key.(uint64)/2) + return uint64(key.(uint64) * key.(uint64) / 2) } func float32Hash(key interface{}) uint64 { - return uint64(key.(float32) * key.(float32)/2) + return uint64(key.(float32) * key.(float32) / 2) } func float64Hash(key interface{}) uint64 { - return uint64(key.(float64) * key.(float64)/2) + return uint64(key.(float64) * key.(float64) / 2) } func complex64Hash(key interface{}) uint64 { r := uint64(real(key.(complex64))) diff --git a/goSTL/data_structure/avlTree/avlTree.go b/goSTL/data_structure/avlTree/avlTree.go index dbbb37b..7c43cf5 100644 --- a/goSTL/data_structure/avlTree/avlTree.go +++ b/goSTL/data_structure/avlTree/avlTree.go @@ -37,7 +37,7 @@ type avlTreer interface { Size() (num int) //返回该二叉树中保存的元素个数 Clear() //清空该二叉树 Empty() (b bool) //判断该二叉树是否为空 - Insert(e interface{}) (b bool) //向二叉树中插入元素e + Insert(e interface{}) (b bool) //向二叉树中插入元素e Erase(e interface{}) (b bool) //从二叉树中删除元素e Count(e interface{}) (num int) //从二叉树中寻找元素e并返回其个数 } @@ -149,7 +149,7 @@ func (avl *AvlTree) Empty() (b bool) { //@receiver avl *avlTree 接受者avlTree的指针 //@param e interface{} 待插入元素 //@return b bool 添加成功? -func (avl *AvlTree) Insert(e interface{}) (b bool){ +func (avl *AvlTree) Insert(e interface{}) (b bool) { if avl == nil { return false } @@ -186,7 +186,7 @@ func (avl *AvlTree) Insert(e interface{}) (b bool){ // 如果该二叉树仅持有一个元素且根节点等价于待删除元素,则将二叉树根节点置为nil //@receiver avl *avlTree 接受者avlTree的指针 //@param e interface{} 待删除元素 -//@return b bool 删除成功 +//@return b bool 删除成功? func (avl *AvlTree) Erase(e interface{}) (b bool) { if avl == nil { return false diff --git a/goSTL/data_structure/trie/node.go b/goSTL/data_structure/trie/node.go new file mode 100644 index 0000000..68474b2 --- /dev/null +++ b/goSTL/data_structure/trie/node.go @@ -0,0 +1,204 @@ +package trie + +//@Title trie +//@Description +// 单词查找树的节点 +// 可通过节点的分叉对string进行查找 +// 增添string时候只需要增删结点即可 +// 当string到终点时存储元素 + +//node树节点结构体 +//该节点是trie的树节点 +//结点存储到此时的string的前缀数量 +//以son为分叉存储下属的string +//该节点同时存储其元素 +type node struct { + num int + 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 + } + if n.son[idx] == nil { + n.son[idx] = newNode(nil) + } + b = n.son[idx].insert(s, p+1, e) + if b { + n.num++ + } + 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 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/goSTL/data_structure/trie/trie.go b/goSTL/data_structure/trie/trie.go new file mode 100644 index 0000000..dceec73 --- /dev/null +++ b/goSTL/data_structure/trie/trie.go @@ -0,0 +1,243 @@ +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 + 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.Size() > 0 { + return false + } + return true +} + +//@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 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 +}