二叉树的基本算法

192 阅读2分钟

二叉树的先序、中序、后序遍历

1. 基本规则

  • 先序:任何子树的处理顺序都是,先头节点、再左子树、然后右子树
  • 中序:任何子树的处理顺序都是,先左子树、再头节点、然后右子树
  • 后序:任何子树的处理顺序都是,先左子树、再右子树、然后头节点

2. 递归实现

public static void pre(Node head) {
   if (head == null) {
      return;
   }
   System.out.println(head.value);
   pre(head.left);
   pre(head.right);
}

public static void in(Node head) {
   if (head == null) {
      return;
   }
   in(head.left);
   System.out.println(head.value);
   in(head.right);
}

public static void pos(Node head) {
   if (head == null) {
      return;
   }
   pos(head.left);
   pos(head.right);
   System.out.println(head.value);
}

3. 非递归实现

public static void pre(Node head) {
   System.out.print("pre-order: ");
   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);
         }
      }
   }
   System.out.println();
}

public static void in(Node cur) {
   System.out.print("in-order: ");
   if (cur != null) {
      Stack<Node> stack = new Stack<Node>();
      while (!stack.isEmpty() || cur != null) {
         if (cur != null) {
            stack.push(cur);
            cur = cur.left;
         } else {
            cur = stack.pop();
            System.out.print(cur.value + " ");
            cur = cur.right;
         }
      }
   }
   System.out.println();
}

public static void pos1(Node head) {
   System.out.print("pos-order: ");
   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);
         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();
}

将 N 叉树编码为二叉树

class Codec {
   // Encodes an n-ary tree to a binary tree.
   public TreeNode encode(Node root) {
      if (root == null) {
         return null;
      }
      TreeNode head = new TreeNode(root.val);
      head.left = en(root.children);
      return head;
   }
   // 把孩子都通过right指针连接
   private TreeNode en(List<Node> children) {
      TreeNode head = null;
      TreeNode cur = null;
      for (Node child : children) {
         TreeNode tNode = new TreeNode(child.val); // 生成二叉树节点
         if (head == null) {  // 只会执行一次
            head = tNode;
         } else {
            cur.right = tNode;
         }
         cur = tNode; // cur来到新节点
         cur.left = en(child.children); // 再递归生成新节点的孩子
      }
      return head;
   }

   // Decodes your binary tree to an n-ary tree.
   public Node decode(TreeNode root) {
      if (root == null) {
         return null;
      }
      return new Node(root.val, de(root.left));
   }
   // 从第一个兄弟节点开始,构建所有的孩子
   public List<Node> de(TreeNode root) {
      List<Node> children = new ArrayList<>();
      while (root != null) {
         Node cur = new Node(root.val, de(root.left)); // 每个兄弟都递归生成孩子
         children.add(cur);
         root = root.right; // 一直向右,遍历所有兄弟
      }
      return children;
   }

}

求二叉树最宽的层有多少个节点

public static int maxWidthNoMap(Node head) {
   if (head == null) {
      return 0;
   }
   Queue<Node> queue = new LinkedList<>();
   queue.add(head);
   Node curEnd = head; // 当前层,最右节点是谁
   Node nextEnd = null; // 下一层,最右节点是谁
   int max = 0;
   int curLevelNodes = 0; // 当前层的节点数
   while (!queue.isEmpty()) {
      Node cur = queue.poll();
      if (cur.left != null) {
         queue.add(cur.left);
         nextEnd = cur.left; // 提前记录下一层的最右侧节点
      }
      if (cur.right != null) {
         queue.add(cur.right);
         nextEnd = cur.right; // 提前记录下一层的最右侧节点
      }
      curLevelNodes++;
      if (cur == curEnd) {  // 如果遍历到的节点是当前层最后一个
         max = Math.max(max, curLevelNodes); // 结算当前层节点数
         curLevelNodes = 0;  // 清零,准备计算下一层
         curEnd = nextEnd;
      }
   }
   return max;
}

后继节点

二叉树结构如下定义:

class lass Node {
    V value;
    Node left;
    Node right;
    Node parent;
}

给你二叉树中的某个节点,返回该节点的后继节点(中序遍历的下一个节点)

public static Node getSuccessorNode(Node node) {
    if (node == null) {
        return node;
    }
    if (node.right != null) { // 其一,右树最左的节点
        return getLeftMost(node.right);
    } else { // 其二,无右树,如果某个节点左树最右是node,那么此节点就是后继节点
        Node parent = node.parent;
        while (parent != null && parent.right == node) { // 当前节点是其父亲节点右孩子
            node = parent;
            parent = node.parent;
        }
        return parent;
    }
}

public static Node getLeftMost(Node node) {
    if (node == null) {
        return node;
    }
    while (node.left != null) {
        node = node.left;
    }
    return node;
}