二叉树

72 阅读2分钟

递归树

代码:

public static void f(Node head) {
    // 回到父节点再进行判断
    if(head == null) {
        return;
    }
    // 回到父节点再访问左节点
    f(head.left);
    // 回到父节点再访问右节点
    f(head.right);
     // 执行完再回到父节点
}

例子:(递归序)

image.png

先序遍历(先中后都是在递归树的基础上遍历的)

先序:头左右

非递归实现步骤:

  1. 每次从栈中弹出一个节点cur
  2. 打印cur
  3. 先右再左(没有就什么也不做,继续弹出)
  4. 循环
public static void preOrderUnRecur(Node head) {
    if(head != null){
        Stack<Node> stack = new Stack<Node>();
        stack.add(head);
        while(!stack.isEmpty()) {
            head = stack.pop();
            System.out.print(head.value + "");
            if(head.right != null){
                stack.push(head.right);
            }
            if(head.left != null){
                stack.push(head.left);
            }
        }
    }
}

中序遍历

中序:左头右

非递归实现步骤: 每颗子树整棵树左边界进栈,依次弹出的过程中,打印,对弹出节点右树循环。(看弹出节点的右树有没有,有的话,进栈,这个节点左边界进展)

public static void inOrderUnRecur(Node Head){
    if(head != null) {
        Stack<Node> stack = new Stack<Node>(); // 创建栈
        while(!stack.isEmpty() || head != null) {
            if(head != null) {
                stack.push(head); // 头节点入栈
                head = head.left; // 获取当前节点所有左节点
            } else {
                head = stack.pop(); // 栈弹出
                System.out.print(head.value + ""); // 打印
                head = head.right; // 获取弹出节点的右树(会走上面条件)
            }
        }
    }
    System.out.println();
}

步骤图: image.png

后序遍历

后序:左右头 非递归实现步骤:

  1. 弹cur
  2. 当前节点cur放到收集栈
  3. 先左再右
  4. 循环
public static void posOrderUnRecur1(Node head) {
    if(head != null){
        Stack<Node> s1 = new Stack<Node>();
        Stack<Node> s2 = new Stack<Node>(); // 收集栈
        s1.push(head); 
        while(!s1.isEmpty()){
            head = s1.pop(); // 弹出
            s2.push(head); // 当前节点cur放到收集栈
            if(head.left != null) {
                s1.push(head.left);
            }
            if(head.right != null) {
                s1.push(head.right);
            }
        }
        while(!s2.isEmpty()) {
            System.out.print(s2.pop().value + "");
        }
    }
    System.out.println();
}

步骤:

宽度优先遍历

public static void w (Node head) {
    if(head == null){
        return;
    }
    Queue<Node> queue = new linkedList<>(); // 创建队列
    queue.add(head);
    while(!queue.isEmpty()) {
        Node cur = queue.poll(); // 队列弹出的值
        System.out.println(cur.value);
        if(cur.left != null) {
            queue.add(cur.left); // 左节点进队列
        }
        if(cur.right != null) {
            queue.add(cur.right); // 右节点进队列
        }
    }
}

步骤图: image.png

二叉树最大宽度

public static void w (Node head) {
    if(head == null){
        return;
    }
    Queue<Node> queue = new linkedList<>(); // 创建队列
    queue.add(head);
    HashMap<Node, Integer> levelMap = new HashMap(); // 创建哈希表
    levelMap.push(head, 1); // 当前节点 节点所在的层数
    int curLevel = 1; // 当前层数
    int curLevelNodes = 0; // 当前层数节点数
    int max = Integer.MIN_VALUE; // 某一层的节点最多 多少个
    while(!queue.isEmpty()) {
        Node cur = queue.poll(); // 队列弹出的值
        int curNodeLevel = levelMap.get(cur); // 当前节点所在的层数
        if(curNodeLevel = curLevel) { // 弹出节点所在的层数还在我要计算的层数
            curLevelNodes++; // 节点数++
        } else { // 下一层了
            max = Math.max(max, curLevelNodes)
            curLevel++;
            curLevelNodes = 1;
        }
        if(cur.left != null) {
            levelMap.put(cur.left, curNodeLevel+1); // 进栈时,记录节点所在的层数
            queue.add(cur.left); // 左节点进队列
        }
        if(cur.right != null) {
            levelMap.put(cur.right, curNodeLevel+1); // 进栈时,记录节点所在的层数
            queue.add(cur.right); // 右节点进队列
        }
    }
}

判断二叉树是搜索二叉树

递归写法:

public static int preValue = Integer.MIN_VALUE;

public static boolean checkBST(Node head) {
    if(head == null) {
        return true;
    }
    boolean isLeftBst = checkBST(head.left); // 判断左子树是不是搜索二叉树
    if(!isLeftBst) {
        return false;
    }
    if(head.value <= preValue) {
        return false;
    } else {
        preValue = head.value;
    }
    return checkBST(head.right);
}

非递归写法:(中序遍历)

public static boolean checkBST3(Node head) {
    if(head != null){
       int preValue = Integer.MIN_VALUE;
       
       Stack<Node> stack = new Stack<Node>();
       while(!stack.isEmpty() || head != null) {
           if(head != null){
               stack.push(head);
               head = head.left;
           } else {
               head = stack.pop();
               
               // 新增搜索二叉树的判断条件(代码原来是中序遍历)
               if(head.value <= preValue){
                   return false;
               } else {
                   preValue = head.value;
               }
               
               head = head.right;
           }
       }
    }
    return true;
}

判断二叉树是完全二叉树

  1. 任意节点,有右孩子没有左孩子,返回false
  2. 在第一个条件不违规的情况下,如果遇到了第一个左右孩子不全的情况下,后续的所有节点必须是叶节点
public static boolean isCBT(Node head) {
    if(head == null){
        return true;
    }
    LinkedList<Node> queue = new LinkedList<>(); // 创建队列
    
    // 是否遇到过左右两个孩子不双全的节点
    boolean leaf = false;
    Node l = null;
    Node r = null;
    queue.add(head);
    while(!queue.isEmpty()){
        head = queue.poll();
        l = head.left;
        r = head.right;
        if(
            // 左右两个孩子不双全 && 不是叶节点(又发现当前节点有孩子)
            (leaf && (l != null || r != null))
            ||
            (l == null && r != null)
        ) {
            return false;
        }
        
        if(l != null){
            queue.add(l);
        }
        if(r != null){
            queue.add(r);
        }
        if(l == null || r == null) {
            leaf = true;
        }
    }
    return true;
}

反转二叉树

image.png

初始数据

 
let list = {
  id: "4",
  left: {
    id: "2",
    left: {
      id: "1",
      left: null,
      right: null,
    },
    right: {
      id: "3",
      left: null,
      right: null,
    },
  },
  right: {
    id: "7",
    left: {
      id: "6",
      left: null,
      right: null,
    },
    right: {
      id: "9",
      left: null,
      right: null,
    },
  },
};

定义一个临时的变量tmp,用于交换 left 和 right 递归处理 left和right,,如果传递的值是null停止处理

function reverseBTree(node) {
  if (!node) {
    return;
  }
  let tmp = node.left;
  node.left = node.right;
  node.right = tmp;
  reverseBTree(node.left);
  reverseBTree(node.right);
}