mirror of
https://github.com/hlccd/goSTL.git
synced 2025-01-18 22:09:33 +08:00
新增了前缀基数树的实现,利用并发控制锁保证线程安全
This commit is contained in:
parent
fdb989f4c0
commit
eedc78e4d8
308
goSTL/data_structure/radix/node.go
Normal file
308
goSTL/data_structure/radix/node.go
Normal file
@ -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
|
||||||
|
}
|
277
goSTL/data_structure/radix/radix.go
Normal file
277
goSTL/data_structure/radix/radix.go
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
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按'/'进行分割,并去掉第一个即去掉"",随后一次按照分层结果进行查找
|
||||||
|
r.mutex.Lock()
|
||||||
|
m, ok = r.root.mate(s, 0)
|
||||||
|
r.mutex.Unlock()
|
||||||
|
return m, ok
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user