新增了前缀基数树Rax的实现,同时修缮了之前实现的数据结构中出现的一些错误

This commit is contained in:
hlccd 2021-12-19 23:39:10 +08:00 committed by GitHub
parent 29dbcd9702
commit 2aec515340
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 539 additions and 3 deletions

View File

@ -0,0 +1,221 @@
package rax
//@Title rax
//@Description
// 前缀基数树的节点
// 可通过节点的分叉对string进行查找
// 增添string时候需要增删结点,同时将结点内置的map中增删删除对应的string即可
// 当string到终点时存储元素
//node树节点结构体
//该节点是rax的树节点
//结点存储到此时的string的前缀数量
//son存储其下属分叉的子结点指针
//该节点同时存储其元素
type node struct {
name string //以当前结点的string内容
num int //以当前结点为前缀的数量
value interface{} //当前结点存储的元素
sons map[string]*node //该结点下属结点的指针
}
//@title newNode
//@description
// 新建一个前缀基数树节点并返回
// 将传入的元素e作为该节点的承载元素
//@receiver nil
//@param name string 该节点的名字,即其对应的string
//@param e interface{} 承载元素e
//@return n *node 新建的单词查找树节点的指针
func newNode(name string, e interface{}) (n *node) {
return &node{
name: name,
num: 0,
value: e,
sons: make(map[string]*node),
}
}
//@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+n.name)
}
for _, son := range n.sons {
es = append(es, son.inOrder(s+n.name+"/")...)
}
return es
}
//@title insert
//@description
// 以node前缀基数树节点做接收者
// 从n节点中继续插入以s为索引的元素e,且当前抵达的string位置为p
// 若该层string为""时候视为失败
// 当到达s终点时进行插入,如果此时node承载了元素则插入失败,否则成功
// 当未到达终点时,根据当前抵达的位置去寻找其子结点继续遍历即可
// 当插入失败且对应子结点为新建节点时则需要删除该子结点
//@receiver n *node 接受者node的指针
//@param ss []string 待删除元素的索引s的按'/'进行分层的索引集合
//@param p int 索引当前抵达的位置
//@param e interface{} 待插入元素e
//@return b bool 是否插入成功?
func (n *node) insert(ss []string, p int, e interface{}) (b bool) {
if p == len(ss) {
if n.value != nil {
return false
}
n.value = e
n.num++
return true
}
s := ss[p]
if s == "" {
return false
}
//从其子结点的map中找到对应的方向
son, ok := n.sons[s]
if !ok {
//不存在,新建并放入map中
son = newNode(s, nil)
n.sons[s] = son
}
//从子结点对应方向继续插入
b = son.insert(ss, p+1, e)
if b {
n.num++
} else {
if !ok {
//插入失败且该子节点为新建结点则需要删除该子结点
delete(n.sons, s)
}
}
return b
}
//@title erase
//@description
// 以node前缀基数树节点做接收者
// 从n节点中继续删除以s为索引的元素e,且当前抵达的string位置为p
// 若该层string为""时候视为失败
// 当到达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.value != nil {
n.value = nil
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
// 若该层string为""时候视为失败
// 当到达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 {
n.num -= num
if son.num <= 0 {
//删除后子结点的num<=0即该节点无后续存储元素,可以销毁
delete(n.sons, s)
}
}
return num
}
//@title count
//@description
// 以node前缀基数树节点做接收者
// 从n节点中继续查找以s为前缀索引的元素e,且当前抵达的string位置为p
// 若该层string为""时候视为查找失败
// 当到达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 find
//@description
// 以node前缀基数树节点做接收者
// 从n节点中继续查找以s为前缀索引的元素e,且当前抵达的string位置为p
// 若该层string为""时候视为查找失败
// 当到达s终点时返回其承载的元素即可
// 当未到达终点时,根据当前抵达的位置去寻找其子结点继续遍历即可,当其分叉为nil则直接返回nil
//@receiver n *node 接受者node的指针
//@param ss []string 待删除元素的索引s的按'/'进行分层的索引集合
//@param p int 索引当前抵达的位置
//@return e interface{} 该索引所指向的元素e
func (n *node) find(ss []string, p int) (e interface{}) {
if p == len(ss) {
return n.value
}
//从map中找到对应下子结点位置并递归进行查找
s := ss[p]
son, ok := n.sons[s]
if !ok || son == nil {
return 0
}
return son.find(ss, p+1)
}

View File

@ -0,0 +1,303 @@
package rax
//@Title rax
//@Description
// 前缀基数树-Rax
// 以多叉树的形式实现,根据'/'进行string分割,将分割后的string数组进行段存储
// 插入的string首字符必须为'/'
// 任意一段string不能为""
// 结点不允许覆盖,即插入值已经存在时会插入失败,需要先删除原值
// 使用互斥锁实现并发控制
import (
"github.com/hlccd/goSTL/utils/iterator"
"strings"
"sync"
)
//rax前缀基数树结构体
//该实例存储前缀基数树的根节点
//同时保存该树已经存储了多少个元素
//整个树不允许重复插入,若出现重复插入则直接失败
type rax struct {
root *node //前缀基数树的根节点指针
size int //当前已存放的元素数量
mutex sync.Mutex //并发控制锁
}
//rax前缀基数树容器接口
//存放了rax前缀基数树可使用的函数
//对应函数介绍见下方
type raxer interface {
Iterator() (i *Iterator.Iterator) //返回包含该rax的所有string
Size() (num int) //返回该rax中保存的元素个数
Clear() //清空该rax
Empty() (b bool) //判断该rax是否为空
Insert(s string, e interface{}) (b bool) //向rax中插入string并携带元素e
Erase(s string) (b bool) //从rax中删除以s为索引的元素e
Delete(s string) (num int) //从rax中删除以s为前缀的所有元素
Count(s string) (num int) //从rax中寻找以s为前缀的string单词数
Find(s string) (e interface{}) //从rax中寻找以s为索引的元素e
}
//@title New
//@description
// 新建一个rax前缀基数树容器并返回
// 初始根节点为nil
//@receiver nil
//@param nil
//@return r *rax 新建的rax指针
func New() (r *rax) {
return &rax{
root: newNode("", nil),
size: 0,
mutex: sync.Mutex{},
}
}
//@title Iterator
//@description
// 以rax前缀基数树做接收者
// 将该rax中所有存放的string放入迭代器中并返回
//@receiver r *rax 接受者rax的指针
//@param nil
//@return i *iterator.Iterator 新建的Iterator迭代器指针
func (r *rax) 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
// 以rax前缀基数树做接收者
// 返回该容器当前含有元素的数量
// 如果容器为nil返回0
//@receiver r *rax 接受者rax的指针
//@param nil
//@return num int 容器中实际使用元素所占空间大小
func (r *rax) Size() (num int) {
if r == nil {
return 0
}
if r.root == nil {
return 0
}
return r.size
}
//@title Clear
//@description
// 以rax前缀基数树做接收者
// 将该容器中所承载的元素清空
// 将该容器的size置0
//@receiver r *rax 接受者rax的指针
//@param nil
//@return nil
func (r *rax) Clear() {
if r == nil {
return
}
r.mutex.Lock()
r.root = newNode("", nil)
r.size = 0
r.mutex.Unlock()
}
//@title Empty
//@description
// 以rax前缀基数树做接收者
// 判断该rax是否含有元素
// 如果含有元素则不为空,返回false
// 如果不含有元素则说明为空,返回true
// 如果容器不存在,返回true
//@receiver r *rax 接受者rax的指针
//@param nil
//@return b bool 该容器是空的吗?
func (r *rax) Empty() (b bool) {
if r == nil {
return true
}
return r.size == 0
}
//@title Insert
//@description
// 以rax前缀基数树做接收者
// 向rax插入以string类型的s为索引的元素e
// 插入的string的首字符必须为'/',且中间按'/'分割的string不能为""
// 若存在重复的s则插入失败,不允许覆盖
// 否则插入成功
//@receiver r *rax 接受者rax的指针
//@param s string 待插入元素的索引s
//@param e interface{} 待插入元素e
//@return b bool 添加成功?
func (r *rax) Insert(s string, e interface{}) (b bool) {
if r == nil {
return false
}
if len(s) == 0 {
return false
}
if s[0] != '/' {
return false
}
//将s按'/'进行分割,并去掉第一个即去掉"",随后一次按照分层结果进行插入
ss := strings.Split(s, "/")[1:]
r.mutex.Lock()
if r.root == nil {
//避免根节点为nil
r.root = newNode("", nil)
}
//从根节点开始插入
b = r.root.insert(ss, 0, e)
if b {
//插入成功,size+1
r.size++
}
r.mutex.Unlock()
return b
}
//@title Erase
//@description
// 以rax前缀基数树做接收者
// 从rax树中删除元素以s为索引的元素e
// 用以删除的string索引的首字符必须为'/'
//@receiver r *rax 接受者rax的指针
//@param s string 待删除元素的索引
//@return b bool 删除成功?
func (r *rax) Erase(s string) (b bool) {
if r.Empty() {
return false
}
if len(s) == 0 {
return false
}
if s[0] != '/' {
return false
}
//将s按'/'进行分割,并去掉第一个即去掉"",随后一次按照分层结果进行删除
ss := strings.Split(s, "/")[1:]
if r.root == nil {
//根节点为nil即无法删除
return false
}
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
// 以rax前缀基数树做接收者
// 从rax树中删除以s为前缀的所有元素
// 用以删除的string索引的首字符必须为'/'
//@receiver r *rax 接受者rax的指针
//@param s string 待删除元素的前缀
//@return num int 被删除的元素的数量
func (r *rax) Delete(s string) (num int) {
if r.Empty() {
return 0
}
if len(s) == 0 {
return 0
}
if s[0] != '/' {
return 0
}
if r.root == nil {
return 0
}
//将s按'/'进行分割,并去掉第一个即去掉"",随后一次按照分层结果进行删除
ss := strings.Split(s, "/")[1:]
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
// 以rax前缀基数树做接收者
// 从rax中查找以s为前缀的所有string的个数
// 用以查找的string索引的首字符必须为'/'
// 如果存在以s为前缀的则返回大于0的值即其数量
// 如果未找到则返回0
//@receiver r *rax 接受者rax的指针
//@param s string 待查找的前缀s
//@return num int 待查找前缀在rax树中存在的数量
func (r *rax) Count(s string) (num int) {
if r.Empty() {
return 0
}
if r.root == nil {
return 0
}
if len(s) == 0 {
return 0
}
if s[0] != '/' {
return 0
}
//将s按'/'进行分割,并去掉第一个即去掉"",随后一次按照分层结果进行查找
ss := strings.Split(s, "/")[1:]
r.mutex.Lock()
num = r.root.count(ss, 0)
r.mutex.Unlock()
return num
}
//@title Find
//@description
// 以rax前缀基数树做接收者
// 从rax中查找以s为索引的元素e,找到则返回e
// 用以查找的string索引的首字符必须为'/'
// 如果未找到则返回nil
//@receiver r *rax 接受者rax的指针
//@param s string 待查找索引s
//@return ans interface{} 待查找索引所指向的元素
func (r *rax) Find(s string) (e interface{}) {
if r.Empty() {
return nil
}
if len(s) == 0 {
return nil
}
if s[0] != '/' {
return nil
}
if r.root == nil {
return nil
}
//将s按'/'进行分割,并去掉第一个即去掉"",随后一次按照分层结果进行查找
ss := strings.Split(s, "/")[1:]
r.mutex.Lock()
e = r.root.find(ss, 0)
r.mutex.Unlock()
return e
}

View File

@ -109,12 +109,20 @@ func (n *node) insert(s string, p int, e interface{}) (b bool) {
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
}
@ -177,14 +185,15 @@ func (n *node) delete(s string, p int) (num int) {
return 0
}
num = n.son[idx].delete(s, p+1)
if num>0 {
n.num-=num
if num > 0 {
n.num -= num
if n.son[idx].num <= 0 {
n.son[idx] = nil
}
}
return num
}
//@title count
//@description
// 以node单词查找树节点做接收者

View File

@ -117,6 +117,9 @@ func (t *trie) Clear() {
//@param nil
//@return b bool 该容器是空的吗?
func (t *trie) Empty() (b bool) {
if t == nil {
return true
}
return t.size == 0
}
@ -234,7 +237,7 @@ func (t *trie) Delete(s string) (num int) {
// 如果未找到则返回0
//@receiver t *trie 接受者trie的指针
//@param s string 待查找的前缀s
//@return num int 待查找前缀在trie中存在的数量
//@return num int 待查找前缀在trie中存在的数量
func (t *trie) Count(s string) (num int) {
if t == nil {
return 0