在学习AVL树的时候我就有用栈代替递归遍历树的想法了,当时只是觉得可行,奈何被左旋右旋单旋双旋转昏了头,拿递归实现都是硬着头皮做的,今天我实现了这个想法,感觉整个人都升华了。
PS 本篇博文只是博主实现心中突然冒出来的设想的产物,在写之前并没有查看过别的文章,而且写出来后代码也没有进行大量的测试,所以很有可能有大量的bug,不建议观看。
本篇博文的示例使用了一个路由前缀树,具有查找/插入这两个功能。实现可能会有bug,看看思路就行。
那么我讲一讲逻辑,如果看过CSAPP就会知道递归其实就是不断的压栈存数据和弹栈取数据,所以我们完全可以用栈+循环来代替递归。在下面这颗路由前缀树中,查找的逻辑是: 判断当前路由层级是否为最后一层,如果是的话就返回对应的Handler;如果不是则搜寻子节点,将全部匹配的子节点压栈。然后弹栈,开始下一次循环。这个逻辑如果用在二叉树中既可以实现先序遍历也可以实现后序遍历,只要改变一下压栈的顺序就可以了。
其实我觉得没有什么好解释的,蛮简单的,不过理解前是真的不明白,理解后就只觉得: 就这(
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 package route_trieimport ( "strings" "github.com/golang-collections/collections/stack" ) type HandlerFunc *string type Node struct { ISWild bool Path string Children []*Node Handler HandlerFunc } type pairNode struct { Node *Node Index int } func splitPath (path string ) []string { return strings.Split(path, "/" ) } func newNode (path string ) *Node { if len (path) != 0 { if path[0 ] == '*' || path[0 ] == ':' { return &Node{ISWild: true , Path: path, Children: make ([]*Node, 0 )} } else { return &Node{ISWild: false , Path: path, Children: make ([]*Node, 0 )} } } else { return &Node{ISWild: false , Path: path, Children: make ([]*Node, 0 )} } } func (n *Node) searchChild(path string ) *Node { if n.Children == nil { return nil } for _, child := range n.Children { if child == nil { continue } if child.Path == path { return child } } return nil } func (n *Node) searchChildren(path string ) []*Node { children := make ([]*Node, 0 ) for _, child := range n.Children { if child.Path == path || child.ISWild { children = append (children, child) } } return children } func (n *Node) Insert(path string , handler HandlerFunc) { paths := splitPath(path) p_len := len (paths) root := n for i := 0 ; i < p_len; i++ { child := root.searchChild(paths[i]) if child == nil { child = newNode(paths[i]) root.Children = append (root.Children, child) } root = child } root.Handler = handler } func (n *Node) Search(path string ) HandlerFunc { paths := splitPath(path) p_len := len (paths) nstack := stack.New() index := 0 root := &pairNode{Node: n, Index: index} for { if root == nil { return nil } index = root.Index if index == p_len { return root.Node.Handler } children := root.Node.searchChildren(paths[index]) for _, child := range children { nstack.Push(&pairNode{Index: index + 1 , Node: child}) } if nstack.Peek() != nil { root = nstack.Pop().(*pairNode) } else { root = nil } } }
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package mainimport ( "fmt" route_tire "route_trie" ) func main () { var root route_tire.Node root.Children = make ([]*route_tire.Node, 0 ) s := "hey!" root.Insert("/*hello/hey" , &s) fmt.Println(root.Children) fmt.Println("This is handler: " ) fmt.Println(*root.Search("/hello/hey" )) }
结果:
1 2 3 4 go run main.go [0xc0000ae040] This is handler: hey!