题目
序列化–将树节点的值转化成列表或队列
反序列化–将序列化之后的列表还原回树的结构
分析:
可以选择一种方式,如前序 中序 后续的方式将节点的值加入到队列
分序列化也必然要按照序列同样的遍历方式还原成树
为了反序列化方便,需要将空节点补齐为nil,包括叶子节点的左右孩子
代码:
深度优先 前序遍历方式序列化
package main
import (
"github.com/goSTL/Data_structure/queue"
"fmt"
// "math"
// "reflect"
//
)
type TreeNode struct {
Value int
// 左子树指针
left *TreeNode
// 右子树指针
right *TreeNode
}
//压入队列,前序,注意压入的是value值,空的节点我这里为了方便就用nil占位了
func process(tree *TreeNode,q *queue.Queue) {
if tree == nil{
q.Push(nil)
}else{
q.Push(tree.Value)
// fmt.Println(q)
process(tree.left,q)
process(tree.right,q)
}
//&{[18 5 3 <nil> <nil> 8 <nil> 12 <nil> 15 <nil> <nil> 20 <nil> 4 <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil>] 0 17 32 {0 0}}
}
//深度优先序列化,放到队列,叶子节点的左右孩子要补齐为nil,
func treetoliresult(tree *TreeNode)*queue.Queue {
q := queue.New()
process(tree,q)
return q
}
//反序列化,建树,与序列化同样的遍历顺序,
func buildtree(q *queue.Queue) *TreeNode {
var tree TreeNode
for ! q.Empty(){
tmp:=(q.Pop())
//递归方法,nil就返回换到另一边的子树
if tmp == nil{
return nil
}
switch tmp.(type){//注意reflect的格式 .(type)
case int:
v,ok:=tmp.(int)//一定要加这一句才能转换,强转类型
if ok{
tree.Value=v
tree.left=buildtree(q)//同样先建左子树
tree.right=buildtree(q)//再建右子树
fmt.Printf("%#v\n",tree)
fmt.Printf(" left %#v\n",tree.left)
fmt.Printf(" right %#v\n",tree.right)
return &tree//因为这里没返回,找到半夜12点,记得记得一定在这里返回建好的一个节点
}
}
}
return &tree
}
序列化之后:
&{[18 5 3 <nil> <nil> 8 <nil> 12 <nil> 15 <nil> <nil> 20 <nil> 4
<nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil>
<nil> <nil> <nil> <nil> <nil> <nil>] 0 17 32 {0 0}}
反序列化(重建树过程):
main.TreeNode{Value:3, left:(*main.TreeNode)(nil), right:(*main.TreeNode)(nil)}
left (*main.TreeNode)(nil)
right (*main.TreeNode)(nil)
main.TreeNode{Value:15, left:(*main.TreeNode)(nil), right:(*main.TreeNode)(nil)}
left (*main.TreeNode)(nil)
right (*main.TreeNode)(nil)
main.TreeNode{Value:12, left:(*main.TreeNode)(nil), right:(*main.TreeNode)(0xc000004180)}
left (*main.TreeNode)(nil)
right &main.TreeNode{Value:15, left:(*main.TreeNode)(nil), right:(*main.TreeNode)(nil)}
main.TreeNode{Value:8, left:(*main.TreeNode)(nil), right:(*main.TreeNode)(0xc000004150)}
left (*main.TreeNode)(nil)
right &main.TreeNode{Value:12, left:(*main.TreeNode)(nil), right:(*main.TreeNode)(0xc000004180)}
main.TreeNode{Value:5, left:(*main.TreeNode)(0xc0000040c0), right:(*main.TreeNode)(0xc000004120)}
left &main.TreeNode{Value:3, left:(*main.TreeNode)(nil), right:(*main.TreeNode)(nil)}
right &main.TreeNode{Value:8, left:(*main.TreeNode)(nil), right:(*main.TreeNode)(0xc000004150)}
main.TreeNode{Value:4, left:(*main.TreeNode)(nil), right:(*main.TreeNode)(nil)}
left (*main.TreeNode)(nil)
right (*main.TreeNode)(nil)
main.TreeNode{Value:20, left:(*main.TreeNode)(nil), right:(*main.TreeNode)(0xc0000042b8)}
left (*main.TreeNode)(nil)
right &main.TreeNode{Value:4, left:(*main.TreeNode)(nil), right:(*main.TreeNode)(nil)}
main.TreeNode{Value:18, left:(*main.TreeNode)(0xc0000040a8), right:(*main.TreeNode)(0xc000004288)}
left &main.TreeNode{Value:5, left:(*main.TreeNode)(0xc0000040c0), right:(*main.TreeNode)(0xc000004120)}
right &main.TreeNode{Value:20, left:(*main.TreeNode)(nil), right:(*main.TreeNode)(0xc0000042b8)}
建完树后先续遍历:
//先续遍历
func PreOrder(tree *TreeNode) {
if tree == nil {
return
}
// 先打印根节点,当前tree就是根,直接打印
fmt.Print(tree.Value, " ")
// 再打印左子树
PreOrder(tree.left)
// 再打印右字树
PreOrder(tree.right)
}
//18 5 3 8 12 15 20 4
按层序列化
func bfsseriallize(tree *TreeNode)*queue.Queue {
result := queue.New()//系列化结果队列
q := queue.New()//辅助队列,用于控制节点的压入弹出
if tree == nil{
result.Push(nil)
}else{
q.Push(tree)
result.Push(tree.Value)
}
for !q.Empty(){
tmp:=q.Pop()
switch tmp.(type){//注意reflect的格式 .(type)
case *TreeNode:
v,ok:=tmp.(*TreeNode)//一定要加这一句才能转换,强转类型
if ok{
// fmt.Println(v)
if v.left !=nil{
q.Push(v.left)
result.Push(v.left.Value)
}else{
result.Push(nil)
}
if v.right !=nil{
q.Push(v.right)
result.Push(v.right.Value)
}else{
result.Push(nil)
}
}
}
}
fmt.Println(result)
// fmt.Println(q)
return result
}
//花了我两天的代码,node全部使用指针才可以
//花了我两天的代码,node全部使用指针才可以
//用两个队列,一个是序列化后的队列,另一个是空队列,先从序列化队列弹出head,加辅助入空队列,注意一定是指针
//再从辅助队列弹出head,此事序列化队列的前两个值就是头结点的左右孩子,将他们弹出,建好一个子树,然后将左右孩子放入辅助队列,因为下一次要建他两的左右孩子节点,依次循环,知道建完树
func bfsbuild(q *queue.Queue) *TreeNode {
var head *TreeNode//这里一定要用指针,才能令下面第一次取出的node等于head,下面的指针连接才会链起来
t := queue.New()//辅助队列,控制节点压入弹出,与上面的q一样
//先从队列拿出头结点,放入t队列,注意是指针,头结点弹出的时候,连续弹出后面两位,就是头结点的左右孩子
//再将左右孩子压入t,因为还需要给孩子节点赋左右子节点,形成完整的链
tmp:=(q.Pop())
if tmp != nil{
n:=gennode(tmp)
head=n
t.Push(head)
}
//拿出root
//18 5 20 3 8 <nil> 4 <nil> <nil> <nil> 12 <nil> <nil> <nil> 15 <nil> <nil>
var node *TreeNode
for ! t.Empty(){
temp:=t.Pop()
node=gennode(temp)
// (*node).Value+=1//我在这里将node的值+1,打印出来head的值成了19,所以说head==node,底层是
//取左节点
fmt.Printf("head %p\n",head)//head 0xc000096138 head等于第一次的node,因为head进入队列的时候是指针,取出的时候也是指针,后面的是结构体的值
fmt.Printf("node %p\n",node)//node 0xc000096138 只要第一次node等于head,后面就不是了
// res1:= reflect.DeepEqual(head, node) //deepequal是判断底层是同一个struct,域和域上的值完全相等,可以说明两个struct是同一个
// fmt.Printf("equal %#V\n",res1)//bool=true
tmp:=(q.Pop())
node.left=gennode(tmp)
//建好左孩子节点,不为空的话加入t,下次弹出链上左右孩子节点
if node.left !=nil{
t.Push(node.left)
}
//取右节点
tmp=(q.Pop())
//建好右孩子节点,不为空的话加入t,下次弹出链上左右孩子节点
node.right=gennode(tmp)
if node.right !=nil{
t.Push(node.right)
}
// fmt.Printf("node %#V\n",node)
// fmt.Printf("LEFT %#V\n",node.left)
// fmt.Printf("right %#V\n",node.right)
// fmt.Printf("size %#V\n",t.Size())
// fmt.Printf("size %#V\n",t)
// list=append(list,node)
}
return head
}
//从interface{}取出的值断言后建节点
func gennode(s interface{}) *TreeNode{
switch s.(type){//注意reflect的格式 .(type)
case int:
v,ok:=s.(int)//一定要加这一句才能转换,强转类型
if ok{
var node *TreeNode=new(TreeNode)
(*node).Value=v
// fmt.Printf("zh %#v",v)
return node
}
case TreeNode:
v,ok:=s.(TreeNode)//一定要加这一句才能转换,强转类型
if ok{
// fmt.Printf("zhizhizhizhizhizhizhi %#v\n",v)
return &v
}
case *TreeNode:
v,ok:=s.(*TreeNode)//一定要加这一句才能转换,强转类型
if ok{
// fmt.Printf("指针指针指针指针指针指针 %#v\n",v)
return v
}
case nil:
return nil
}
return nil
}
func main() {
// 根节点
var root TreeNode
root.Value=18
// 一级左子树
var left1 TreeNode
left1.Value=5
root.left = &left1
// 一级右子树
var right1 TreeNode
right1.Value=20
root.right = &right1
var right2 TreeNode
right2.Value=4
right1.right = &right2
// 二级左子树
var left2 TreeNode
left2.Value=3
left1.left = &left2
// 三级右子树
var left3 TreeNode
left3.Value=8
left1.right = &left3
//四级右子树
var left4 TreeNode
left4.Value=12
left3.right = &left4
//五级右子树
var left5 TreeNode
left5.Value=15
left4.right = &left5
// q:=treetoliresult(&root)
// fmt.Println(q)
// t:=buildtree(q)
// PreOrder(t)
result:=bfsseriallize(&root)
t:=bfsbuild(result)
PreOrder(t)
// fmt.Printf("%#V\n",t)
// fmt.Printf("%#V\n",t.left)
// fmt.Printf("%#V\n",t.right)
// fmt.Printf("%#V\n",t.left.left)
// fmt.Printf("%#V\n",t.right.right)
}
输出:
&{[18 5 20 3 8 <nil> 4 <nil> <nil> <nil> 12 <nil> <nil> <nil> 15 <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil>] 0 17 32 {0 0}}
head 0xc00009e138
node 0xc00009e138
node &{%!V(int=18) %!V(*main.TreeNode=&{5 <nil> <nil>}) %!V(*main.TreeNode=&{20 <nil> <nil>})}
LEFT &{%!V(int=5) %!V(*main.TreeNode=<nil>) %!V(*main.TreeNode=<nil>)}
right &{%!V(int=20) %!V(*main.TreeNode=<nil>) %!V(*main.TreeNode=<nil>)}
head 0xc00009e138
node 0xc00009e150
node &{%!V(int=5) %!V(*main.TreeNode=&{3 <nil> <nil>}) %!V(*main.TreeNode=&{8 <nil> <nil>})}
LEFT &{%!V(int=3) %!V(*main.TreeNode=<nil>) %!V(*main.TreeNode=<nil>)}
right &{%!V(int=8) %!V(*main.TreeNode=<nil>) %!V(*main.TreeNode=<nil>)}
head 0xc00009e138
node 0xc00009e168
node &{%!V(int=20) %!V(*main.TreeNode=<nil>) %!V(*main.TreeNode=&{4 <nil> <nil>})}
LEFT %!V(*main.TreeNode=<nil>)
right &{%!V(int=4) %!V(*main.TreeNode=<nil>) %!V(*main.TreeNode=<nil>)}
head 0xc00009e138
node 0xc00009e1c8
node &{%!V(int=3) %!V(*main.TreeNode=<nil>) %!V(*main.TreeNode=<nil>)}
LEFT %!V(*main.TreeNode=<nil>)
right %!V(*main.TreeNode=<nil>)
head 0xc00009e138
node 0xc00009e1e0
node &{%!V(int=8) %!V(*main.TreeNode=<nil>) %!V(*main.TreeNode=&{12 <nil> <nil>})}
LEFT %!V(*main.TreeNode=<nil>)
right &{%!V(int=12) %!V(*main.TreeNode=<nil>) %!V(*main.TreeNode=<nil>)}
head 0xc00009e138
node 0xc00009e240
node &{%!V(int=4) %!V(*main.TreeNode=<nil>) %!V(*main.TreeNode=<nil>)}
LEFT %!V(*main.TreeNode=<nil>)
right %!V(*main.TreeNode=<nil>)
head 0xc00009e138
node 0xc00009e2a0
node &{%!V(int=12) %!V(*main.TreeNode=<nil>) %!V(*main.TreeNode=&{15 <nil> <nil>})}
LEFT %!V(*main.TreeNode=<nil>)
right &{%!V(int=15) %!V(*main.TreeNode=<nil>) %!V(*main.TreeNode=<nil>)}
head 0xc00009e138
node 0xc00009e300
node &{%!V(int=15) %!V(*main.TreeNode=<nil>) %!V(*main.TreeNode=<nil>)}
LEFT %!V(*main.TreeNode=<nil>)
right %!V(*main.TreeNode=<nil>)
前序输出:18 5 3 8 12 15 20 4