递归遍历二叉树非常简单,只要交换调用顺序即可,那么非递归呢,我这里都是借用栈的思想实现的
前序遍历
实现:第一次访问的时候就记录到结果数组中,然后进栈,依次访问其左孩子,知道左孩子为空弹出栈顶,访问其右孩子,循环这个过程,直到栈为空,root也为空
代码:
func (root *TreeNode) preorder() []int{ //非递归前序遍历
res:=[]int{}
if root==nil{
return res
}
stack:=[]*TreeNode{} //定义一个栈储存节点信息
for root!=nil || len(stack)!=0{
if root!=nil{
res=append(res,root.data)
stack=append(stack,root)
root=root.Lchild
}else{
root=stack[len(stack)-1]
stack=stack[:len(stack)-1]
root=root.Rchild
}
}
return res
}
中序遍历
实现:根前序很相似,只是改变一下顺序,从栈中弹出的时候(第二次访问)才放进结果数组
代码:
func (root *TreeNode) inorder()[]int{
res:=[]int{}
if root==nil{
return res
}
stack:=[]*TreeNode{}
for root!=nil || len(stack)!=0{
if root!=nil{
stack=append(stack,root)
root=root.Lchild
}else{
root=stack[len(stack)-1]
res=append(res,root.data)
stack=stack[:len(stack)-1]
root=root.Rchild
}
}
return res
}
后序遍历
前序中序都比较简单,而且很相似,后序就稍微复杂一下了
实现:这里要增加一个辅助节点来节点上一次放入结果数组的值,当一个节点左右都是空的时候,就可以放入结果集,当上一个放入结果集的节点是他的孩子节点的时候,说明他的孩子已经访问完成了,到这里就是第三次了就可以放入了,还有一点要注意的是,当一个节点的左右不为空时,要先加入右孩子,再加入左孩子,这样才能先访问左孩子。
func (root *TreeNode)postorder() []int {
res:=[]int{}
if root==nil{
return res
}
stack:=[]*TreeNode{}
pre:=&TreeNode{}
stack=append(stack,root)
for len(stack)!=0{
cur:=stack[len(stack)-1]
if (cur.Lchild==nil && cur.Rchild==nil) || (pre!=nil &&(pre==cur.Lchild || pre==cur.Rchild)){
res=append(res,cur.data)
pre=cur
stack=stack[:len(stack)-1]
}else{
if cur.Rchild!=nil{
stack=append(stack,cur.Rchild)
}
if cur.Lchild!=nil{
stack=append(stack,cur.Lchild)
}
}
}
return res
}