遍歷二叉樹(遞迴,非遞迴都有)
阿新 • • 發佈:2019-02-17
主要描述一下非遞迴,遞迴在下面的總的程式碼裡有:
因為非遞迴都用到了棧,先貼一下棧的程式碼
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)
}