算法61-树的序列化与反序列化

题目

序列化–将树节点的值转化成列表或队列

反序列化–将序列化之后的列表还原回树的结构

分析:

可以选择一种方式,如前序 中序 后续的方式将节点的值加入到队列

分序列化也必然要按照序列同样的遍历方式还原成树

在这里插入图片描述
为了反序列化方便,需要将空节点补齐为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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值