首页 > 技术文章 > 【数据结构系列】——二叉树的各个遍历及序列化与反序列化

Candycan 2021-04-13 21:03 原文

二叉树的各种遍历,序列化与反序列化

序列化与反序列化:将变成语言中的结构体序列化成JSON字符串,存入缓存或者通过网络发送给远程服务,消费者接受JSON字符串然后进行范徐丽恶化,就可以得到原始数据了。目的是,已某种固定格式组织字符串,使得数据可以独立于编程语言。

序列化:吧结构化的数据“打平”,其实就是在考察二叉树的遍历方式

反序列化,将字符串还原出二叉树

前序遍历

前序遍历框架:

void traverse(TreeNode root){
	if(root == null) return;
	//前序遍历的代码
	traverse(root.left);
	traverse(root.right);
}

序列化,需要将一颗二叉树打平成一个字符串

//代表分割符的字符
    String SEP = ",";
    //代表null空指针的字符
    String NULL = "#";
    /**
     * 主函数,将二叉树序列化为字符串
     */
    String serialize(TreeNode root){
        //用于拼接字符串
        StringBuilder sb = new StringBuilder();
        serialize(root,sb);
        return sb.toString();
    }
    /**
     * 将二叉树打平为字符串
     */
    void serialize(TreeNode root,StringBuilder sb){
        if (root == null){
            sb.append(NULL).append(SEP);
            return;
        }
        /**
         * 前序遍历
         */
        sb.append(root.val).append(SEP);
        serialize(root.left,sb);
        serialize(root.right,sb);
    }

反序列化

先确定根节点root,然后根据前序遍历的规则,递归生成左右子树

/**
     * 主函数,将字符串反序列化为二叉树结构
     * @param data
     * @return
     */
    TreeNode deserialize_pre(String data){
        //将字符串转化为列表
        LinkedList<String> nodes = new LinkedList<>();
        for (String s : data.split(SEP)) {
            nodes.addLast(s);
        }
        return deserialize(nodes);
    }

    /**
     * 辅助函数,通过nodes列表构造二叉树
     * @param nodes
     * @return
     */
    private TreeNode deserialize(LinkedList<String> nodes) {
        if (nodes.isEmpty())
            return null;
        /**
         * 前序遍历
         */
        //列表最左侧就是根节点
        String first = nodes.removeFirst();
        if (first.equals(NULL))
            return null;
        TreeNode root = new TreeNode(Integer.parseInt(first));
        root.left = deserialize(nodes);
        root.right = deserialize(nodes);
        return root;
    }

后序遍历

后序遍历框架

void traverse(TreeNode root){
    if(root == null)
        return;
    traverse(root.left);
    traverse(root.right);
}

序列化:

String SEP=",";
String NULL="#";
String serialize+post(TreeNode root){
    StringBuilder sb = new StringBuilder();
    serialize(root,sb);
    return sb.toString();
}
void serialize(TreeNode root,StringBuilder sb){
    if(root == null){
        sb.append(NULL).append(SEP);
        return;
    }
    serialize(root.left,sb);
    serialize(root.right,sb);
    sb.append(root.val).append(SEP);
}

反序列化:

从后往前取出列表元素,一定要先构造root.right子树,后构造root.left子树


    /**
     * 主函数,将字符串反序列化为二叉树结构
     * @param data
     * @return
     */
    TreeNode deserialize_post(String data){
        //将字符串转化为列表
        LinkedList<String> nodes = new LinkedList<>();
        for (String s : data.split(SEP)) {
            nodes.addLast(s);
        }
        return deserialize(nodes);
    }

    /**
     * 辅助函数,通过nodes列表构造二叉树
     * @param nodes
     * @return
     */
    private TreeNode deserialize(LinkedList<String> nodes) {
        if (nodes.isEmpty())
            return null;
        //从后往前取出元素
        String last = nodes.removeLast();
        if (last.equals(NULL))
            return null;
        TreeNode root = new TreeNode(Integer.parseInt(last));
        root.right = deserialize(nodes);
        root.left = deserialize(nodes);

        return root;
    }

中序遍历

中序遍历不能反序列化,因为root的值被夹在两颗子树的中间,我们不知道确切的索引位置,无法找到root节点,无法进行反序列化

中序遍历序列化:

void serialize(TreeNode root,StringBuilder sb){
    if(root == null){
        sb.append(NULL).append(SEP);
        return;
    }
    serialize(root.left,sb);
    sb.append(root.val).append(SEP);
    serialize(root.right,sb);
}

层序遍历

层序遍历框架:

void traverse(TreeNode root){
	if(root == null) return;
	//初始化列表,将root加入队列
	Queue<TreeNode> q = new LinkedList<>();
	q.offer(root);
	while(!q.isEmpty()){
		TreeNode cur = q.poll();
		
        /**
        层序遍历代码位置
        */
        if(cur == null) continue;
        System.out.prontlin(cur.val);
        q.offer(cur.left);
        q.offer(cur.right);
	}
}

序列化:

 //代表分割符的字符
    String SEP = ",";
    //代表null空指针的字符
    String NULL = "#";
    /**
     * 主函数,将二叉树序列化为字符串
     */
    String serialize_level(TreeNode root){
        //用于拼接字符串
        StringBuilder sb = new StringBuilder();
        //初始化队列,将root加入队列
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);

        while (!q.isEmpty()){
            TreeNode cur = q.poll();
            //层序遍历
            if (cur == null){
                sb.append(NULL).append(SEP);
                continue;
            }
            sb.append(cur.val).append(SEP);
            q.offer(cur.left);
            q.offer(cur.right);
        }
        return sb.toString();
    }

反序列化

    /**
     * 主函数,将字符串反序列化为二叉树结构
     * @param data
     * @return
     */
    TreeNode deserialize_level(String data){
        if (data.isEmpty())
            return null;
        String[] nodes = data.split(SEP);
        //第一个元素就是root的值
        TreeNode root = new TreeNode(Integer.parseInt(nodes[0]));
        //队列q记录父节点,将root加入队列
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        for (int i = 1; i < nodes.length ; i++) {
            //队列中存的是父节点
            TreeNode parent = q.poll();
            //父节点对应的左侧子节点的值
            String left = nodes[i++];
            if (!left.equals(NULL)){
                parent.left = new TreeNode(Integer.parseInt(left));
                q.offer(parent.left);
            }else {
                parent.left = null;
            }
            //父节点对应的右侧子节点的值
            String right = nodes[i++];
            if (!right.equals(NULL)){
                parent.right = new TreeNode(Integer.parseInt(right));
                q.offer(parent.right);
            }else {
                parent.right = null;
            }
        }
        return root;
    }

推荐阅读