go:实现前缀树

2019-11-22 14:52:19 浏览数 (1)

url路由的副产品。

代码语言:javascript复制
package utils

/*
PrefixTree 前缀树
使用姿势:
tree := utils.BuildTree([]string{
    "/yuedu/account",
    "/yuedu",
    "/yuedu/master",
})

fmt.Println(tree.Match("/yuedu"))
fmt.Println(tree.Match("/yuedu/details"))
fmt.Println(tree.Match("/yuedu/account"))
fmt.Println(tree.Match("/yuedu/account/user"))
fmt.Println(tree.Match("/yuedu/master/"))
result:
/yuedu true
/yuedu false
/yuedu/account true
/yuedu/account false
/yuedu/master false
*/
type PrefixTree struct {
    root *treeNode
}

// BuildTree 生成这棵前缀树
func BuildTree(keys []string) *PrefixTree {
    tree := new(PrefixTree)
    root := makeNode()
    for _, key := range keys {
        buildNode(key, root)
    }
    tree.root = root
    return tree
}

// Match 尝试匹配一个Path,返回最终匹配的结果和是否完全匹配
func (t PrefixTree) Match(path string) (string, bool) {
    tpnode := t.root
    result := ""
    for _, pathpart := range path {
        _, ok := tpnode.subNode[pathpart]
        if !ok {
            return result, false
        }
        tpnode = tpnode.subNode[pathpart]
        if tpnode.value != "" {
            result = tpnode.value
        }
    }
    return result, tpnode.value != ""
}

type treeNode struct {
    subNode map[rune]*treeNode
    value   string
}

func makeNode() *treeNode {
    node := new(treeNode)
    node.subNode = make(map[rune]*treeNode)
    return node
}

func buildNode(key string, root *treeNode) {
    tpnode := root
    for _, keypart := range key {
        _, ok := tpnode.subNode[keypart]
        if ok {
            tpnode = tpnode.subNode[keypart]
        } else {
            tpnode.subNode[keypart] = makeNode()
            tpnode = tpnode.subNode[keypart]
        }
    }
    tpnode.value = key
}
url

0 人点赞