赞
踩
package Morris
import (
"fmt"
"math"
"testing"
)
/*
morris 遍历,遍历完一棵二叉树,可以实现二叉树的先序中序后序,可以做到时间复杂度O(N),额外空间复杂度O(1)
笔试以最快Ac为目标,面试时候可以吹牛逼
kmp 的 morris 和 morris遍历中的morris 是一个人
二叉树的遍历,递归非递归都需要额外空间
时间复杂度 O(N) , 额外空间复杂度 O(h) 和高度相关
流程
当前节点cur,一开始 cur来到整棵树的头
1.如果cur 无左树,cur直接向右移动 cur = cur.Right
2.如果cur 有左树,找到cur左树最右节点 mostRight [ 。。。 .Right.Right....]
2.1 如果mostRight 的右指针指向nil, mostRight.Right = cur, cur = cur.Left 改指针走向
2.2 mostRight 的右指针 指向cur, mostRight.Right = nil , cur = cur.Right
3. cur = nil 时候, 循环结束
1
/ \
2 3
/ \ / \
4 5 6 7
忘掉先序,中序,后序概念
cur 依次到达每个节点的顺序 叫 morris序
------------------------------------------------------
1
/ \
2 3
/ \ / \
4 5 6 7
------------------------------------------------------
morris序: 1
有左树
1 < cur
/ \
2 3
/ \ / \
4 5 6 7
来到左树最右节点
------------------------------------------------------
morris序: 1 2
左树最右节点的右指针为nil
1 < cur
/ /| \
cur> 2 | 3
/ \ | / \
4 5 | 6 7
\__|
左树最右节点的右指针指向cur,cur 来到cur的 left
1
/ /| \
cur> 2 | 3
/ \ | / \
4 5 | 6 7
\__|
------------------------------------------------------
有左树
1
/ /| \
cur> 2 | 3
/ /|\ | / \
4 | 5 | 6 7
\__| \__|
来到左树最右节点,让左树最右节点的右指针指向cur
------------------------------------------------------
morris序: 1 2 4
1
/ /| \
2 | 3
/ /|\ | / \
cur> 4 | 5 | 6 7
\__| \__|
cur没有左树,cur向右移动,来到2,但是2已经被走过了
morris序: 1 2 4 2
1
/ /| \
cur> 2 | 3
/ /|\ | / \
4 | 5 | 6 7
\__| \__|
让右指针指向nil,cur往右移动,来到5
1
/ /| \
cur> 2 | 3
/ \ | / \
4 5 | 6 7
\ \__|
nil
1
/ /| \
cur> 2 | 3
/ \ | / \
4 5 | 6 7
/|\__|
|
cur
morris序: 1 2 4 2 5
cur 没有最右节点,来到1
1 <cur
/ /| \
cur> 2 | 3
/ \ | / \
4 5 | 6 7
\__|
morris序: 1 2 4 2 5 1
恢复5的右节点指向nil,cur 往右移动
1
/ \
2 3 <cur
/ \ / \
4 5 6 7
morris序: 1 2 4 2 5 1 3
1
/ \
2 3
/ \ / /| \
4 5 6 | 7
/|\_|
|
cur
morris序: 1 2 4 2 5 1 3 6
morris序: 1 2 4 2 5 1 3 6 3
1
/ \
2 3 <cur
/ \ / \
4 5 6 7
1
/ \
2 3
/ \ / \
4 5 6 7 <cur
morris序: 1 2 4 2 5 1 3 6 3 7
什么样的树都可以遍历完
任何一棵树,只要有左树,都会来到2次
没有左树的节点,只会来到1次
一个节点往右走,再也不会回来了
*/
type Node struct {
Value int
Left *Node
Right *Node
}
func morris(head *Node) {
if head == nil {
return
}
cur := head
var mostRight *Node
for cur != nil { // cur 不断往左或往右跳,一旦为空就出来
mostRight = cur.Left //cur 有没有左树
if mostRight != nil {
// 找到cur 左树上真实的最右节点
for mostRight.Right != nil && mostRight.Right != cur { // 第一次 nil, 第二次 cur
mostRight = mostRight.Right
}
// 从for中出来,mostRight 一定是cur左树上的最右节点
if mostRight.Right == nil {
mostRight.Right = cur
cur = cur.Left
continue // continue 最外层for
}else { // mostRight.Right != nil => mostRight.Right == cur
mostRight.Right = nil
}
}
cur = cur.Right
}
}
func TestMorris(t *testing.T) {
head := &Node{
Value: 1,
Left: &Node{
Value: 2,
Left: &Node{
Value: 4,
Left: nil,
Right: nil,
},
Right: &Node{
Value: 5,
Left: nil,
Right: nil,
},
},
Right: &Node{
Value: 3,
Left: &Node{
Value: 6,
Left: nil,
Right: nil,
},
Right: &Node{
Value: 7,
Left: nil,
Right: nil,
},
},
}
morrisPre(head)
morrisIn(head)
morrisPos(head)
}
// 先序 第一次来到节点的时候打印,第二次来到的时候不打印
// 中序 第二次来到节点的时候打印,能回到2次的不打印(有左树的),第二次回归时打印,只能来到1次的直接打印(没有左树的)
// 后序 比较复杂
func morrisIn(head *Node) { //中序
if head == nil {
return
}
cur := head
var mostRight *Node
for cur != nil { // cur 不断往左或往右跳,一旦为空就出来
mostRight = cur.Left //cur 有没有左树
if mostRight != nil {
// 找到cur 左树上真实的最右节点
for mostRight.Right != nil && mostRight.Right != cur { // 第一次 nil, 第二次 cur
mostRight = mostRight.Right
}
// 从for中出来,mostRight 一定是cur左树上的最右节点
if mostRight.Right == nil {
mostRight.Right = cur
cur = cur.Left
continue // continue 最外层for
}else { // mostRight.Right != nil => mostRight.Right == cur
mostRight.Right = nil
}
}
fmt.Print(cur.Value , "\t")
cur = cur.Right
}
fmt.Println()
}
func morrisPre(head *Node) { //先序
if head == nil {
return
}
cur := head
var mostRight *Node
for cur != nil { // cur 不断往左或往右跳,一旦为空就出来
mostRight = cur.Left //cur 有没有左树
if mostRight != nil {
// 找到cur 左树上真实的最右节点
for mostRight.Right != nil && mostRight.Right != cur { // 第一次 nil, 第二次 cur
mostRight = mostRight.Right
}
// 从for中出来,mostRight 一定是cur左树上的最右节点
if mostRight.Right == nil {
mostRight.Right = cur
fmt.Print(cur.Value,"\t")
cur = cur.Left
continue // continue 最外层for
}else { // mostRight.Right != nil => mostRight.Right == cur
mostRight.Right = nil
}
} else {
fmt.Print(cur.Value,"\t")
}
cur = cur.Right
}
fmt.Println()
}
// 打印时机,就放在能回到自己两次,且第二次回到自己的时候
// 打印他左树的右边界,逆序打印
// 整棵树可以被子树的右边界分解掉
// 不能放到栈里,用 [ 反转链表 ] 打印完再调回来 时间复杂度O(N)
func morrisPos(head *Node) { //后序
if head == nil {
return
}
cur := head
var mostRight *Node
for cur != nil { // cur 不断往左或往右跳,一旦为空就出来
mostRight = cur.Left //cur 有没有左树
if mostRight != nil {
// 找到cur 左树上真实的最右节点
for mostRight.Right != nil && mostRight.Right != cur { // 第一次 nil, 第二次 cur
mostRight = mostRight.Right
}
// 从for中出来,mostRight 一定是cur左树上的最右节点
if mostRight.Right == nil {
mostRight.Right = cur
cur = cur.Left
continue // continue 最外层for
}else { // mostRight.Right != nil => mostRight.Right == cur
mostRight.Right = nil
printEdge(cur.Left)
}
}
cur = cur.Right
}
printEdge(head)
fmt.Println()
}
// 线索二叉树
func printEdge(head *Node) {
tail := reverseEdge(head)
cur := tail
for cur != nil {
fmt.Print(cur.Value, "\t")
cur = cur.Right
}
reverseEdge(tail)
}
func reverseEdge(from *Node) *Node {
var pre, next *Node
for from != nil {
next = from.Right
from.Right = pre
pre = from
from = next
}
return pre
}
/*
扩展: 判断一棵树是不是搜索二叉树
*/
//任何一个节点左树头节点比自己小,右树头节点比自己大
func morrisIsBST(head *Node) bool {
if head == nil {
return true
}
cur := head
var mostRight *Node
pre := (*int)(nil)
for cur != nil { // cur 不断往左或往右跳,一旦为空就出来
mostRight = cur.Left //cur 有没有左树
if mostRight != nil {
// 找到cur 左树上真实的最右节点
for mostRight.Right != nil && mostRight.Right != cur { // 第一次 nil, 第二次 cur
mostRight = mostRight.Right
}
// 从for中出来,mostRight 一定是cur左树上的最右节点
if mostRight.Right == nil {
mostRight.Right = cur
cur = cur.Left
continue // continue 最外层for
}else { // mostRight.Right != nil => mostRight.Right == cur
mostRight.Right = nil
}
}
if pre != nil && *pre >= cur.Value {
return false
}
*pre = cur.Value
cur = cur.Right
}
return true
}
/*
一棵二叉树,所有叶节点到头部距离最短的(二叉树的最小高度)
*/
/*
方法1,二叉树的递归套路
*/
func minHeight1(head *Node) int {
if head == nil {
return 0
}
return p(head)
}
func p(x *Node) int {
if x.Left == nil && x.Right == nil {
return 1
}
//左右子树起码有一个不为空
leftH := math.MinInt
if x.Left != nil {
leftH = p(x.Left)
}
rightH := math.MaxInt
if x.Right != nil {
rightH = p(x.Right)
}
return 1 + Min(leftH,rightH)
}
func Min(a, b int) int {
if a > b {
return b
}
return a
}
/*
整个过程用有限几个变量
1 cur 高度
2 cur 此时是叶节点,记录一下高度, Min(min, curH)
*/
func minHeight2forMorris(head *Node) int {
if head == nil {
return 0
}
cur := head
var mostRight *Node
curLevel := 0
minHeight := math.MaxInt
for cur != nil { // cur 不断往左或往右跳,一旦为空就出来
mostRight = cur.Left // cur 有没有左树
if mostRight != nil {
rightBoardSize := 1
// 找到cur 左树上真实的最右节点
for mostRight.Right != nil && mostRight.Right != cur { // 第一次 nil, 第二次 cur
rightBoardSize++
mostRight = mostRight.Right
}
// 从for中出来,mostRight 一定是cur左树上的最右节点
if mostRight.Right == nil { // 第一次到达
curLevel++
mostRight.Right = cur
cur = cur.Left
continue // continue 最外层for
}else { // mostRight.Right != nil => mostRight.Right == cur
//第二次到达
if mostRight.Left == nil {
minHeight = Min(minHeight,curLevel)
}
curLevel -= rightBoardSize
mostRight.Right = nil
}
}else { // 只有一次到达
curLevel++
}
cur = cur.Right
}
finalRight := 1
cur = head
for cur.Right != nil {
finalRight++
cur = cur.Right
}
if cur.Left == nil && cur.Right == nil {
minHeight = Min(minHeight,finalRight)
}
return minHeight
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。