主要描述一下非递归,递归在下面的总的代码里有:
因为非递归都用到了栈,先贴一下栈的代码
const stackSize int = 22 //栈的容量
type TreeNode struct { //树结点
Left *TreeNode
Value int
Right *TreeNode
}
type Stack struct { //栈结构
Size int
Values []*TreeNode
}
func CreateStack() Stack{ //创建栈
s := Stack{}
s.Size = stackSize
return s
}
func (s *Stack) IsFull() bool { //栈满
return len(s.Values) == s.Size
}
func (s *Stack) IsEmpty() bool { //栈空
return len(s.Values) == 0
}
func (s *Stack) Push(a *TreeNode) error { //入栈
if s.IsFull() {
return errors.New("Stack is full,push failed")
}
s.Values = append(s.Values,a)
return nil
}
func (s *Stack) Pop() (*TreeNode,error) {//出栈,并返回其值
if s.IsEmpty() {
return nil ,errors.New("Out of index,len(stack) is 0")
}
res := s.Values[len(s.Values)-1]
s.Values = s.Values[:len(s.Values)-1]
return res,nil
}
func (s *Stack) Peek() (*TreeNode,error) {//查看栈顶元素
if s.IsEmpty() {
return nil ,errors.New("Out of index,len(stack) is 0")
}
return s.Values[len(s.Values)-1],nil
}
一、先根遍历的非递归算法:步骤如下:
1、创建一个栈对象,将根节点入栈;
2、当栈为非空时,将栈顶结点弹出栈并访问该结点;
3、对当前访问的非空左孩子结点相继依次访问(不需要入栈),并将访问结点的非空右孩子结点入栈
4、重复执行步骤②和步骤③,直到栈为空为止
func PreStackTraverse(t *TreeNode){//先根遍历,非递归
if t != nil {
S := CreateStack()
S.Push(t)
for !S.IsEmpty() {
T,_ := S.Pop()
fmt.Printf("%d ",T.Value)
for T != nil {
if T.Left != nil {
fmt.Printf("%d ",T.Left.Value)
}
if T.Right != nil {
S.Push(T.Right)
}
T = T.Left
}
}
}
fmt.Println()
}
二、中根遍历的非递归算法:步骤如下:
1、创建一个栈对象,将根节点入栈;
2、当栈为非空时,将根结点的非空左孩子相继进栈;
3、栈顶结点出栈并访问栈顶结点,并使该栈顶结点的非空右孩子结点入栈
4、重复执行步骤②和步骤③,直到栈为空为止
//中根遍历,非递归
func MidStackTraverse(t *TreeNode){
if t != nil {
S := CreateStack()
S.Push(t)
for !S.IsEmpty() {
top,_ :=S.Peek()
for top != nil { //将栈顶结点的所有左孩子结点入栈
S.Push(top.Left)
top,_= S.Peek()
}
S.Pop() //空结点退栈
if !S.IsEmpty() {
T,_ := S.Pop()
fmt.Printf("%d ",T.Value)
S.Push(T.Right)
}
}
}
fmt.Println()
}
三、后根遍历的非递归算法:
便于理解点:
flag : 当栈中加入右孩子之后,该右孩子的左孩子也要跟着加入栈中,flag为false标记加入了一个右孩子,跳出访问栈顶的循环,将该结点的左孩子加入栈中。否则flag为true,可以继续判断该栈顶
p : 刚刚被访问的结点,当一个结点可以被访问时,要么其右孩子为空,要么p指向其右孩子
步骤如下:
1、创建一个栈对象,根节点进栈,p赋初值null;
2、若栈非空,则栈顶结点的非空左孩子相继进栈;
3、若栈非空,查看栈顶结点,若栈顶结点的右孩子为空,或与p相等,则将栈顶结点弹出栈并访问它,同时将p指向该结点,并设置flag为true。否则将栈顶结点的右孩子(1个)压入栈中,并置flag为false
4、若flag==true,重复执行3,否则,重复执行步骤2和3,直到栈为空。
//后根遍历,非递归
func PostStackTraverse(t *TreeNode) {
if t != nil {
S := CreateStack()
S.Push(t)
var flag bool
var p *TreeNode
for !S.IsEmpty() {
top,_ := S.Peek()
for top != nil { //将栈顶结点的所有左孩子结点入栈
S.Push(top.Left)
top,_= S.Peek()
}
S.Pop()
for !S.IsEmpty() {
T,_ := S.Peek()
if T.Right == nil || T.Right == p {
fmt.Printf("%d ",T.Value)
S.Pop()
flag = true
p = T //p指向刚被访问的结点
}else {
S.Push(T.Right)
flag = false //有右孩子进栈了
}
if !flag { //退出该循环
break
}
}
}
}
fmt.Println()
}
完整代码:
package main
import (
"fmt"
"errors"
)
const stackSize int = 22 //栈的容量
type TreeNode struct {
Left *TreeNode
Value int
Right *TreeNode
}
type Stack struct { //栈结构
Size int
Values []*TreeNode
}
func CreateStack() Stack{ //创建栈
s := Stack{}
s.Size = stackSize
return s
}
func (s *Stack) IsFull() bool { //栈满
return len(s.Values) == s.Size
}
func (s *Stack) IsEmpty() bool { //栈空
return len(s.Values) == 0
}
func (s *Stack) Push(a *TreeNode) error { //入栈
if s.IsFull() {
return errors.New("Stack is full,push failed")
}
s.Values = append(s.Values,a)
return nil
}
func (s *Stack) Pop() (*TreeNode,error) {//出栈,并返回其值
if s.IsEmpty() {
return nil ,errors.New("Out of index,len(stack) is 0")
}
res := s.Values[len(s.Values)-1]
s.Values = s.Values[:len(s.Values)-1]
return res,nil
}
func (s *Stack) Peek() (*TreeNode,error) {//查看栈顶元素
if s.IsEmpty() {
return nil ,errors.New("Out of index,len(stack) is 0")
}
return s.Values[len(s.Values)-1],nil
}
func (s *Stack) Traverse() {
if s.IsEmpty() {
fmt.Println("Stack is empty")
}else {
fmt.Println(s.Values)
}
}
//建立二叉树
func TreeCreate(i int,arr []int) *TreeNode{
t := &TreeNode{nil,arr[i],nil}
if i<len(arr) && 2*i+1 < len(arr){
t.Left = TreeCreate(2*i+1,arr)
}
if i<len(arr) && 2*i+2 < len(arr) {
t.Right = TreeCreate(2*i+2,arr)
}
return t
}
//先根遍历,递归
func PreTraverse(t *TreeNode){
if t != nil {
fmt.Printf("%d/",t.Value)
PreTraverse(t.Left)
PreTraverse(t.Right)
}
}
//先根遍历,非递归
func PreStackTraverse(t *TreeNode){
if t != nil {
S := CreateStack()
S.Push(t) //根结点入栈
for !S.IsEmpty() {
T,_ := S.Pop() //移除根结点,并返回其值
fmt.Printf("%d ",T.Value) //访问结点
for T != nil {
if T.Left != nil { //访问左孩子
fmt.Printf("%d ",T.Left.Value) //访问结点
}
if T.Right != nil { //右孩子非空入栈
S.Push(T.Right)
}
T = T.Left
}
}
}
fmt.Println()
}
//中根遍历,递归
func MidTraverse(t *TreeNode){
if t != nil {
MidTraverse(t.Left)
fmt.Printf("%d/",t.Value)
MidTraverse(t.Right)
}
}
//中根遍历,非递归
func MidStackTraverse(t *TreeNode){
if t != nil {
S := CreateStack()
S.Push(t)
for !S.IsEmpty() {
top,_ :=S.Peek()
for top != nil { //将栈顶结点的所有左孩子结点入栈
S.Push(top.Left)
top,_= S.Peek()
}
S.Pop() //空结点退栈
if !S.IsEmpty() {
T,_ := S.Pop()
fmt.Printf("%d ",T.Value)
S.Push(T.Right)
}
}
}
fmt.Println()
}
//后根遍历,递归
func PostTraverse(t *TreeNode){
if t != nil {
PostTraverse(t.Left)
PostTraverse(t.Right)
fmt.Printf("%d/",t.Value)
}
}
//后根遍历,非递归
func PostStackTraverse(t *TreeNode) {
if t != nil {
S := CreateStack()
S.Push(t)
var flag bool
var p *TreeNode
for !S.IsEmpty() {
top,_ := S.Peek()
for top != nil { //将栈顶结点的所有左孩子结点入栈
S.Push(top.Left)
top,_= S.Peek()
}
S.Pop()
for !S.IsEmpty() {
T,_ := S.Peek()
if T.Right == nil || T.Right == p {
fmt.Printf("%d ",T.Value)
S.Pop()
flag = true
p = T //p指向刚被访问的结点
}else {
S.Push(T.Right)
flag = false //有右孩子进栈了
}
if !flag { //退出该循环
break
}
}
}
}
fmt.Println()
}
func main(){
arr := []int{3,9,6,8,7,11,1,22,21}
Tree := TreeCreate(0,arr)
fmt.Print("前根,递归:")
PreTraverse(Tree)
fmt.Print(" 前根,非递归:")
PreStackTraverse(Tree)
fmt.Print("中根,递归:")
MidTraverse(Tree)
fmt.Print(" 中根,非递归:")
MidStackTraverse(Tree)
fmt.Print("后根,递归:")
PostTraverse(Tree)
fmt.Print(" 后根,非递归:")
PostStackTraverse(Tree)
}