二叉树基本操作

why

MySQL、Hbase、HashMap等底层分别通过B树、B+树、红黑树等来提高性能
而这些树的基础为二叉树,熟悉二叉树的基本操作后再去学习这些技术会事半功倍

what

二叉树,顾名思义,每个节点最多仅有两个子节点,被广泛应用于搜索的场景
时间复杂度一般为 O(depth) 也就是树的高度
空间复杂度一般为 O(node.number)也就是树的节点数

本篇博客计划记录二叉树的递归/非递归遍历、按层打印,
以及序列化/反序列化、重建二叉树 //此行是还没实现的

HOW

递归方式遍历二叉树

由于递归方式比较简单,因此三种遍历的方式写在一块

     public int[][] convert(TreeNode root) {
        
        
        List qianxuList = new ArrayList();
        List zhongxuList = new ArrayList();
        List houxuList = new ArrayList();

        qianxu(qianxuList,root);
        zhongxu(zhongxuList,root);
        houxu(houxuList,root);
        int [][]result = new int[3][qianxuList.size()];
        for (int i=0; i < qianxuList.size(); i++){
            result [0][i] = qianxuList.get(i);
            result [1][i] = zhongxuList.get(i);
            result [2][i] = houxuList.get(i);
        }
        return result;
    }
    
    //递归前序遍历
    public static void qianxu(List list,TreeNode root) {
        if (null == root)
            return;

        list.add(root.val);
        qianxu(list,root.left);
        qianxu(list,root.right);
    }

    //递归中序遍历
    public static void zhongxu(List list,TreeNode root) {
        if (null == root)
            return;

        zhongxu(list,root.left);
        list.add(root.val);
        zhongxu(list,root.right);
    }

    //递归前序遍历
    public static void houxu(List list,TreeNode root) {
        if (null == root)
            return;
        
        houxu(list,root.left);
        houxu(list,root.right);
        list.add(root.val);
    }
    
    public class TreeNode {
            int val = 0;
            TreeNode left = null;
            TreeNode right = null;
            public TreeNode(int val) {
                this.val = val;
            }
        }

非递归遍历

由于递归遍历的代价相对较大(java里面会用帧栈来存储中间结果),因此非递归遍历的方式还是有学习的必要

  1. 前序遍历二叉树
    ① 将根节点放到栈内
    ② 遍历栈,栈为空则停止
    ③ 进行出栈操作,将当前节点的值记录到集合内
    ④ 若是当前节点的右节点不为空,则进栈;若是当前节点的左节点不为空,也进栈
    ⑤ 重复2-4步骤
    public static void qianxu(List list,TreeNode root) {
            Stack stack = new Stack<>();
            if (null == root)
                return;

        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.pop();
            list.add(node.val);
            if (null != node.right){
                stack.push(node.right);
            }

            if (null != node.left){
                stack.push(node.left);
            }
        }
        }
  1. 中序遍历二叉树
    ① 将根节点放到栈内,判断根节点是否有左子节点,若有则继续往里面放,然后再判断左子节点是否有左子节点,若有则继续重复该
    ② 遍历栈,栈为空则停止
    ③ 进行出栈操作,将当前节点的值记录到集合
    ④ 判断当前节点是否有右子节点,若有则重复1步骤
public static void zhongxu(List list,TreeNode root) {
     Stack stack = new Stack<>();
        if (null == root) return;

        stack.push(root);
        while(null != root.left){
          stack.push(root.left);
          root = root.left;
        }

        while(!stack.isEmpty()){
          TreeNode node = stack.pop();
          list.add(node.val);
          if (null != node.right){
              stack.push(node.right);

              node = node.right;
              while(null != node.left){
                stack.push(node.left);
                node = node.left;
              }
           }
     }
}
  1. 后序遍历二叉树
    ① 创建两个栈分别为栈A和栈B
    ② 将根节点放到栈A
    ③ 遍历栈A,当栈A为空的时候停止
    ④ 栈A出栈,取出节点放到栈B;同时先把该节点的左子节点放到栈A里,再把该节点的右子节点放到栈B里
    ⑤ 重复步骤4直到栈A为空,然后对栈B进行出栈操作即可
public static void houxu(List list,TreeNode root) {
       if (null == root) return;

        Stack stackA = new Stack<>();
        Stack stackB = new Stack<>();

        stackA.push(root);
        while(!stackA.isEmpty()){
          TreeNode node = stackA.pop();
          stackB.push(node);
          if (null != node.left){
              stackA.push(node.left);
          }

          if (null != node.right){
              stackA.push(node.right);
          }
       }

       while(!stackB.isEmpty()){
          TreeNode node = stackB.pop();
          list.add(node.val);
       }
 }

按层遍历二叉树

① 创建一个队列,以及两个指针last和nextLast分别指向当前层的最后一个节点
以及下层最后一个节点,同时定义变量depth用于记录当前遍历的层数
② 将根节点放入队列,指针last和nextLast都指向根节点
③ 遍历队列,直到队列为空才停
④ 取出队列中的节点,存储该节点的值,如果该节点有左右子节点,分别按顺序放到队列里,并且调制nextLast去指向最后加入队列的那个节点;同时如果该节点被last指向,则表示该层已经遍历完毕,depth自增1,last指向nextLast
⑤ 重复4步骤直到队列为空

public static void main(String []args){
       TreeNode treeNode1 = new TreeNode(1);
       TreeNode treeNode2 = new TreeNode(2);
       TreeNode treeNode3 = new TreeNode(3);
       TreeNode treeNode4 = new TreeNode(4);
       TreeNode treeNode5 = new TreeNode(5);
       treeNode1.left = treeNode2;
       treeNode1.right = treeNode3;
       treeNode2.left = treeNode4;
       treeNode2.right = treeNode5;

       int [][]result = printTreeByDepth(treeNode1);
       for (int i=0;i queue = new LinkedList<>();
        TreeNode last = root;
        TreeNode nextLast = root;
        int depth = 0;
        int i = 0; //表示遍历到当前层的第几个节点

        queue.offer(root);
        while(!queue.isEmpty()){
            TreeNode node = queue.poll();
            result[depth][i] = node.val;
            i++;

            if (null != node.left){
                queue.offer(node.left);
                nextLast = node.left;
            }

            if (null != node.right){
                queue.offer(node.right);
                nextLast = node.right;
            }

            if (last == node){
                depth++;
                i=0;
                last = nextLast;
            }

        }
        return result;
    }


    public static int getTreeDepth(TreeNode root){
        int depth = 0;
        if (null == root){
            return depth;
        }else {
            return 1 + Math.max(getTreeDepth(root.left),getTreeDepth(root.right));
        }

    }

你可能感兴趣的:(算法,数据结构,树形结构)