算法6 --- 二叉树(golang)

80 阅读5分钟

递归序

    graph TB

    A((1))
    B((2))
    C((3))
    D((4))
    E((5))
    F((6))
    G((7))
    A-->B
    A-->C
    B-->D
    B-->E
    C-->F
    C-->G

那么我们用递归遍历这个二叉树

package main

import "fmt"

type Node struct {
   value int
   left  *Node
   Right *Node
}

func f(node *Node) {

   if node == nil {
      return
   }
   fmt.Print(node.value)
   f(node.left)
   fmt.Print(node.value)
   f(node.Right)
   fmt.Print(node.value)
}

func main() {
   node1 := &Node{value: 1}
   node2 := &Node{value: 2}
   node3 := &Node{value: 3}
   node4 := &Node{value: 4}
   node5 := &Node{value: 5}
   node6 := &Node{value: 6}
   node7 := &Node{value: 7}

   node1.left = node2
   node1.Right = node3

   node2.left = node4
   node2.Right = node5

   node3.left = node6
   node3.Right = node7

   f(node1)
}

打印结果为: 124442555213666377731 ,每个数都调用三次,这个就是递归序

先序就是 头左右的顺序:1245367 ,等效于递归序每个数字第一次打印

中序就是 左头右的顺序: 4251637, 等效于递归序每个数字第二次打印

后序就是 左右头的顺序:4526731,等效于递归序每个数字第三次打印

任何递归函数都可以改成非递归

先序遍历:创建一个栈,先将1丢入栈中,进入循环:从栈中弹出一个数,打印。再将右节点和左节点依次放入栈中,周而复始。


func stack(head *Node) {
   // 初始化
   var stack []*Node

   //  入栈
   stack = append(stack, head)
   for len(stack) != 0 {
      //弹出
      head = stack[len(stack)-1]
      //出栈
      stack = stack[:len(stack)-1]
      fmt.Print(head.value)
      if head.Right != nil {
         stack = append(stack, head.Right)
      }
      if head.left != nil {
         stack = append(stack, head.left)
      }

   }

}

打印:1245367

后序:先序是头左右,将上面方法调整弹出顺序头右左,依次放入另一个栈中,得到逆序就是左右头

中序:将左边界的数存进stack,然后弹出一个数时打印,并且放入right

package main

import (
   "fmt"
)

type Node struct {
   value int
   left  *Node
   Right *Node
}

func f(node *Node) {

   if node == nil {
      return
   }
   fmt.Print(node.value)
   f(node.left)
   fmt.Print(node.value)
   f(node.Right)
   fmt.Print(node.value)
}

func stack(head *Node) {
   fmt.Println()
   // 初始化
   var stack []*Node

   //  入栈
   stack = append(stack, head)
   for len(stack) != 0 {
      head = stack[len(stack)-1]
      //出栈
      stack = stack[:len(stack)-1]
      fmt.Print(head.value)
      if head.Right != nil {
         stack = append(stack, head.Right)
      }
      if head.left != nil {
         stack = append(stack, head.left)
      }

   }
}

func stackM(head *Node) {
   fmt.Println()
   // 初始化
   var stack []*Node

   for len(stack) != 0 || head != nil {
      if head != nil { //先把左的全部存完
         stack = append(stack, head)
         head = head.left
      } else {
         head = stack[len(stack)-1]
         stack = stack[:len(stack)-1]
         fmt.Print(head.value)

         head = head.Right

      }
   }
}

func stackA(head *Node) {
   fmt.Println()
   // 初始化
   var stack []*Node
   var after []*Node
   //  入栈
   stack = append(stack, head)
   for len(stack) != 0 {
      head = stack[len(stack)-1]
      //出栈
      stack = stack[:len(stack)-1]

      after = append(after, head)

      if head.left != nil {
         stack = append(stack, head.left)
      }
      if head.Right != nil {
         stack = append(stack, head.Right)
      }
   }

   for len(after) != 0 {
      fmt.Print(after[len(after)-1].value)
      after = after[:len(after)-1]
   }
}

func main() {
   node1 := &Node{value: 1}
   node2 := &Node{value: 2}
   node3 := &Node{value: 3}
   node4 := &Node{value: 4}
   node5 := &Node{value: 5}
   node6 := &Node{value: 6}
   node7 := &Node{value: 7}

   node1.left = node2
   node1.Right = node3

   node2.left = node4
   node2.Right = node5

   node3.left = node6
   node3.Right = node7

   f(node1)

   stack(node1)
   stackM(node1)
   stackA(node1)
}

宽度遍历


func w(head *Node) {
   fmt.Println()
   if head == nil {
      return
   }
   var queue []*Node
   queue = append(queue, head)
   for len(queue) != 0 {
      cur := queue[0]
      queue = queue[1:]
      fmt.Print(cur.value)
      if cur.left != nil {
         queue = append(queue, cur.left)
      }
      if cur.Right != nil {
         queue = append(queue, cur.Right)
      }
   }
}

获取最大宽度

package main

import (
   "fmt"
)

type Node struct {
   value int
   left  *Node
   Right *Node
}

func f(node *Node) {

   if node == nil {
      return
   }
   fmt.Print(node.value)
   f(node.left)
   fmt.Print(node.value)
   f(node.Right)
   fmt.Print(node.value)
}

func stack(head *Node) {
   fmt.Println()
   // 初始化
   var stack []*Node

   //  入栈
   stack = append(stack, head)
   for len(stack) != 0 {
      head = stack[len(stack)-1]
      //出栈
      stack = stack[:len(stack)-1]
      fmt.Print(head.value)
      if head.Right != nil {
         stack = append(stack, head.Right)
      }
      if head.left != nil {
         stack = append(stack, head.left)
      }

   }
}

func stackM(head *Node) {
   fmt.Println()
   // 初始化
   var stack []*Node

   for len(stack) != 0 || head != nil {
      if head != nil { //先把左的全部存完
         stack = append(stack, head)
         head = head.left
      } else {
         head = stack[len(stack)-1]
         stack = stack[:len(stack)-1]
         fmt.Print(head.value)

         head = head.Right

      }
   }
}

func stackA(head *Node) {
   fmt.Println()
   // 初始化
   var stack []*Node
   var after []*Node
   //  入栈
   stack = append(stack, head)
   for len(stack) != 0 {
      head = stack[len(stack)-1]
      //出栈
      stack = stack[:len(stack)-1]

      after = append(after, head)

      if head.left != nil {
         stack = append(stack, head.left)
      }
      if head.Right != nil {
         stack = append(stack, head.Right)
      }
   }

   for len(after) != 0 {
      fmt.Print(after[len(after)-1].value)
      after = after[:len(after)-1]
   }
}

func w(head *Node) {
   fmt.Println()
   if head == nil {
      return
   }
   var queue []*Node
   queue = append(queue, head)
   for len(queue) != 0 {
      cur := queue[0]
      queue = queue[1:]
      fmt.Print(cur.value)
      if cur.left != nil {
         queue = append(queue, cur.left)
      }
      if cur.Right != nil {
         queue = append(queue, cur.Right)
      }
   }
}

func getMaxWidth(head *Node) {
   fmt.Println()
   if head == nil {
      return
   }
   var queue []*Node

   queue = append(queue, head)
   levelMap := make(map[*Node]int)
   levelMap[head] = 1
   curLevel, nodeCounts, max := 1, 0, 0

   for len(queue) != 0 {
      cur := queue[0]
      queue = queue[1:]
      nodeLevel := levelMap[cur]

      if nodeLevel == curLevel {
         nodeCounts++
      } else {
         if nodeCounts > max {
            max = nodeCounts
         }
         curLevel++
         nodeCounts = 1
      }

      if cur.left != nil {
         levelMap[cur.left] = nodeLevel + 1
         queue = append(queue, cur.left)
      }

      if cur.Right != nil {
         levelMap[cur.Right] = nodeLevel + 1
         queue = append(queue, cur.Right)
      }
   }
   if nodeCounts > max {
      max = nodeCounts
   }
   fmt.Print(max)

}

func main() {
   node1 := &Node{value: 1}
   node2 := &Node{value: 2}
   node3 := &Node{value: 3}
   node4 := &Node{value: 4}
   node5 := &Node{value: 5}
   node6 := &Node{value: 6}
   node7 := &Node{value: 7}

   node1.left = node2
   node1.Right = node3

   node2.left = node4
   node2.Right = node5

   node3.left = node6
   node3.Right = node7

   f(node1)

   stack(node1)
   stackM(node1)
   stackA(node1)

   w(node1)
   getMaxWidth(node1)
}

判断是否是搜索二叉树

每个节点都大于左,小于右

    graph TB

    A((1))
    B((2))
    C((3))
    D((4))
    E((5))
    F((6))
    G((7))
    D-->B
    D-->F
    B-->A
    B-->C
    F-->E
    F-->G

我们利用中序遍历(左头右)得到1234567的数组,如果它是从小到大排列,则是搜索二叉树

package main

import (
   "fmt"
   "math"
)

type Node struct {
   value int
   left  *Node
   Right *Node
}

var LastValue = math.MinInt

func checkBST(head *Node) bool {
   if head == nil {
      return true
   }
   if !checkBST(head.left) {
      return false
   }

   fmt.Print(head.value)
   if head.value >= LastValue {
      LastValue = head.value
   } else {
      return false
   }

   return checkBST(head.Right)
}

func main() {
   node1 := &Node{value: 1}
   node2 := &Node{value: 2}
   node3 := &Node{value: 3}
   node4 := &Node{value: 4}
   node5 := &Node{value: 5}
   node6 := &Node{value: 6}
   node7 := &Node{value: 7}

   node4.left = node2
   node4.Right = node6

   node2.left = node1
   node2.Right = node3

   node6.left = node5
   node6.Right = node7

   fmt.Print(checkBST(node4))
}

套路

对于所有的树形DP(动态规划),适用于跟左数和右树要信息,就可以得到当前解的题目。

我们根据 条件-返回值 ,就可以实现

如搜索二叉树,条件是当前节点的左树和右树都是BST,当前值要大于左树最大值,当前值要小于右树最小值

所以返回值需要IsBST,min,max


type returnValue struct {
   IsBST bool
   Min   int
   Max   int
}

func checkBST(head *Node) *returnValue {
   if head == nil {
      return nil
   }
   left := checkBST(head.left)
   right := checkBST(head.Right)

   var rV = &returnValue{IsBST: true, Min: head.value, Max: head.value}
   if left != nil {
      if left.IsBST == false || head.value < left.Max {
         rV.IsBST = false
      } else {
         rV.Min = left.Min
      }
   }
   if right != nil {
      if right.IsBST == false || head.value > right.Min {
         rV.IsBST = false
      } else {
         rV.Max = right.Max
      }
   }
   return rV
}

如判断是否满二叉树,条件是所有节点的个数和高度满足 nodes=2^height-1

那么返回值就是nodes,左树节点个数加上右树节点个数加上当前节点个数 height,左树和右树比较高的那个,加上当前的节点1的高度


type fullRetrun struct {
   height int
   nodes  int
}

func fullProcess(head *Node) *fullRetrun {
   var fr = &fullRetrun{
      height: 0,
      nodes:  0,
   }
   if head == nil {
      return fr
   }

   left := fullProcess(head.left)
   right := fullProcess(head.Right)

   fr.height = max(left.height, right.height) + 1
   fr.nodes = left.nodes + right.nodes + 1

   return fr
}

func isFull(head *Node) bool {
   fr := fullProcess(head)
   return fr.nodes == (1<<fr.height - 1)
}

经验

看别人二叉树的代码

拿张纸,拿只笔

他们有多少变量,我们就在纸上画多少个变量

然后根据他的循环在纸上还原出来,比一直硬着看好很多