 
     
     
    任何数据结构都可以用顺序存储和链式存储
class TreeNode<T> {
    T data;
    TreeNode<T> left;
    TreeNode<T> right;
}
class BinTree<T>{
    TreeNode<T> root;
}最常用的存储方式
 
    $n$个结点的二叉链表中,有$n+1$个空链域
class BinTree<T>{
    T[] elements;
}将二叉树转为完全二叉树
虚拟出空结点
将完全二叉树上编号(i)的结点存储在数组的(i-1)位置
空结点对应的数组元素存null
如果是单边树,会很浪费空间,一般不使用这种方法
 
    class Node<T> {
    T data;
    int parent; //父节点的下标
}
class BinTree<T>{
    Node<T>[] elements;
}每个结点都记住父结点在数组中的下标
 
    是数组和链表结合的存储方法
每个结点需要存储它的子结点在数组中的下标链表
class Node<T> {
    T data;
    LinkedList<T> children;
}
class BinTree<T>{
    Node<T>[] elements;
} 
    将双亲表示法和孩子表示法结合起来
class Node<T> {
    T data;
    LinkedList<T> children;
    int parent; //父节点的下标
}
class BinTree<T>{
    Node<T>[] elements;
} 
    另一种链式存储方法
结点的左孩子为从左往右的第一个子结点,右孩子为其兄弟结点
class Node<T> {
    T data;
    Node<T> firstChild;
    Node<T> brothers;
}
class BinTree<T>{
    Node<T> root;
}常用于树转换为二叉树,森林转换为二叉树
 
    任何一个与树对应的二叉树,右子树都为空
 
    先将每个树转为二叉树,再将每个二叉树根节点连接
以二叉链表结构为例
class TreeNode<T> {
    T data;
    TreeNode<T> left;
    TreeNode<T> right;
}
class BinTree<T>{
    TreeNode<T> root;
}void preOrderTraversal(TreeNode<T> node) {
    if (node == null) {
        return;
    }
    System.out.println(node.data);
    preOrderTraversal(node.left);
    preOrderTraversal(node.right);
}void preOrderTraversal() {
    Stack<TreeNode<T>> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()) {
        TreeNode<T> node = stack.pop();
        System.out.println(node.data);
        // 先push右孩子再push左孩子
        // 左孩子先出栈
        if(node.right != null) {
            stack.push(node.right);
        }
        if(node.left != null) {
            stack.push(node.left);
        }
    }
}void inOrderTraversal(TreeNode<T> node) {
    if (node == null) {
        return;
    }
    inOrderTraversal(node.left);
    System.out.println(node.data);
    inOrderTraversal(node.right);
}void inOrderTraversal() {
    Stack<TreeNode<T>> stack = new Stack<>();
    TreeNode<T> node = root;
    while(node != null || !stack.isEmpty()){
        while (node != null) {
            stack.push(node);
            node = node.left;
        }
        node = stack.pop();
        System.out.println(node.data);
        node = node.right;
    }
}void postOrderTraversal(TreeNode<T> node) {
    if (node == null) {
        return;
    }
    postOrderTraversal(node.left);
    postOrderTraversal(node.right);
    System.out.println(node.data);
}void postOrderTraversal() {
    Stack<TreeNode<T>> stack1 = new Stack<>();
    Stack<TreeNode<T>> stack2 = new Stack<>();
    stack1.push(root);
    while (!stack1.isEmpty()) {
        TreeNode<T> node = stack1.pop();
        stack2.push(node);
        if(node.left != null) {
            stack1.push(node.left);
        }
        if(node.right != null) {
            stack1.push(node.right);
        }
    }
    while (!stack2.isEmpty()) {
        TreeNode<T> node = stack2.pop();
        traversal.apply(node.data);
    }
}void levelOrderTraversal() {
    int level = 1;
    while (levelOrderTraversal(root, level)) {
        level++;
    }
}
boolean levelOrderTraversal(TreeNode<T> node, int level) {
    if (node == null) {
        return false;
    }
    if (level == 1) {
        System.out.println(node.data);
        return true;
    }
    boolean left = levelOrderTraversal(node.left, level - 1);
    boolean right = levelOrderTraversal(node.right, level - 1);
    return left || right;
}void levelOrderTraversal() {
    Queue<TreeNode<T>> queue = new LinkedList<>();
    queue.add(root);
    while (!queue.isEmpty()) {
        TreeNode<T> node = queue.poll();
        System.out.println(node.data);
        if (node.left != null) {
            queue.add(node.left);
        }
        if (node.right != null) {
            queue.add(node.right);
        }
    }
}深度优先遍历dfs即为先序遍历,广度优先遍历bfs即为层序遍历
如果增加一些辅助数据域,比如父结点或访问位,也可以不借助其他数据结构进行遍历
使用完全二叉树的性质,编号为$i$的结点,左孩子结点的编号为$2i$,右孩子结点的编号为$2i+1$
数组下标从0开始,树的序号从1开始,所以再加1
<T> TreeNode<T> fromLevelOrder(T[] arrays, int index) {
    if (index < arrays.length) {
        TreeNode<T> node = new TreeNode<>(arrays[index]);
        node.left = fromLevelOrder(arrays, index * 2 + 1);
        node.right = fromLevelOrder(arrays, index * 2 + 2);
        return node;
    }
    return null;
}<T> BinTree<T> fromLevelOrderByQueue(T[] arrays) {
    BinTree<T> tree = new BinTree<>();
    for (T t : arrays) {
        tree.insert(t);
    }
    return tree;
}
void insert(T data) {
    if (root == null) {
        root = new TreeNode<>(data);
        return;
    }
    Queue<TreeNode<T>> queue = new LinkedList<>();
    queue.add(root);
    while (!queue.isEmpty()) {
        TreeNode<T> tmp = queue.poll();
        if (tmp.left == null) {
            tmp.left = new TreeNode<>(data);
            break;
        } else {
            queue.add(tmp.left);
            if (tmp.right == null) {
                tmp.right = new TreeNode<>(data);
                break;
            } else {
                queue.add(tmp.right);
            }
        }
    }
}Huffman树的带权路径长度最短
Huffman树没有度为1的结点,是严格的二叉树
 
     
    度为2的树与二叉树的区别
$n$个结点的二叉链表中有多少空链域
一个含有$n$个结点的$k$叉树,可能的最大深度和最小深度是多少
对于非叶子结点都有左右子树的二叉树,有$n$个叶子结点的树中总共多少个结点
找出满足下列条件的二叉树