跳到主要内容

19、数据结构与算法 - 实战:二叉树2

题目:求已知二叉树高度/深度
思路1:递归计算左子树和右子树的高度,然后找出两棵树中高度的大值,再加一,就是树的高度。

/**
 * 题目:求已知二叉树高度/深度
 * @param root 二叉树的根节点
 * @return 二叉树的高度/深度
 */
public static int getHeight(BinaryTreeNode<Integer> root) {
    /* 基本情况:根节点为空时返回0 */
    if (root == null) {
        return 0;
    }
    /* 计算子树的高度/深度 */
    int leftHeight = getHeight(root.getLeft());
    int rightHeight = getHeight(root.getRight());
    /* 返回子树的高度 */
    if (leftHeight > rightHeight) {
        return (leftHeight + 1);
    } else {
        return (rightHeight + 1);
    }
}
思路2:使用层序遍历,使用null作为每一层的结束标志。

/**
 * 题目:求已知二叉树高度/深度
 * @param root 二叉树的根节点
 * @return 二叉树的高度/深度
 */
public static int getHeightByLevelOrder(BinaryTreeNode<Integer> root) {

    /* 根节点为空则返回0 */
    if (root == null) {
        return 0;
    }

    /* 计算二叉树高度 */
    // 声明并初始化树的层数
    int level = 0;
    // 声明并初始化出队元素
    BinaryTreeNode<Integer> temp = new BinaryTreeNode<Integer>();
    // 声明并初始化存储二叉树节点的队列
    LinkListQueue<BinaryTreeNode<Integer>> queue = new LinkListQueue<BinaryTreeNode<Integer>>();

    // 根节点先入队
    queue.enQueue(root);
    // 标记第一层结束
    queue.enQueue(null);
    // 遍历队列直到为空
    while (!queue.isEmpty()) {
        // 获取出队元素
        temp = queue.deQueue();
        // 检查当前层是否结束
        if (temp == null) {
            // 层数自增
            level++;
            // 为下一层添加结束标志
            if (!queue.isEmpty()) {
                queue.enQueue(null);
            }
        } else {
            // 如果当前节点的左孩子存在则入队
            if (temp.getLeft() != null) {
                queue.enQueue(temp.getLeft());
            }
            // 如果当前节点的右孩子存在则入队
            if (temp.getRight() != null) {
                queue.enQueue(temp.getRight());
            }
        }
    }
    return level;
}
题目:删除二叉树中某个节点
思路:
1.从根节点开始层序遍历,找到要删除的节点
2.找到最深节点,如果有多个最深节点,则选择最后一个最深节点即二叉树最底层最右边的节点
3.用最深节点替换要删除的节点
4.删除最深节点

/**
 * 题目:删除二叉树中某个节点
 * @param root 二叉树的根节点
 * @param data 要删除节点的数据值
 * @return 删除结点后的二叉树根节点
 */
public static BinaryTreeNode<Integer> deleteBinaryTreeNode(BinaryTreeNode<Integer> root, int data) {
    /* 根节点为空则返回空 */
    if (root == null) {
        return null;
    }

    /* 实现二叉树出队入栈 */
    // 声明要删除的节点
    BinaryTreeNode<Integer> deleteNode = null;
    // 声明并初始化出队元素
    BinaryTreeNode<Integer> temp = new BinaryTreeNode<Integer>();
    // 声明并初始化结束标志
    BinaryTreeNode<Integer> end = new BinaryTreeNode<Integer>((int) 'z');
    // 声明并初始化存储二叉树节点的队列
    LinkListQueue<BinaryTreeNode<Integer>> queue = new LinkListQueue<BinaryTreeNode<Integer>>();
    // 声明并初始化存储二叉树节点的栈
    LinkedListStack<BinaryTreeNode<Integer>> stack = new LinkedListStack<BinaryTreeNode<Integer>>();

    // 根节点先入队
    queue.enQueue(root);
    // 标记第一层结束
    queue.enQueue(end);

    // 队列不为空则遍历
    while (!queue.isEmpty()) {
        // 获取出队元素
        temp = queue.deQueue();
        // 检查是否是要删除的节点
        if (temp.getData() == data) {
            deleteNode = temp;
        }
        // 检查当前层是否结束
        if (temp == end) {
            // 为下一层添加结束标志
            if (!queue.isEmpty()) {
                queue.enQueue(end);
            }
        } else {
            // 如果当前节点的左孩子存在则入队
            if (temp.getLeft() != null) {
                queue.enQueue(temp.getLeft());
            }
            // 如果当前节点的右孩子存在则入队
            if (temp.getRight() != null) {
                queue.enQueue(temp.getRight());
            }
        }
        // 将出队元素入栈
        stack.push(temp);
    }

    /* 获取最深节点 */
    // 将最后一层的结束标志去掉
    stack.pop();
    // 声明并初始化最深节点
    BinaryTreeNode<Integer> deepestNode = stack.pop();

    /* 重置删除节点的值即可 */
    deleteNode.setData(deepestNode.getData());

    /* 删除最深节点 */
    while (!stack.isEmpty()) {
        temp = stack.pop();
        if (temp.getLeft() == deepestNode) {
            temp.setLeft(null);
        }
        if (temp.getRight() == deepestNode) {
            temp.setRight(null);
        }
    }
    return root;
}
题目:用非递归算法获取二叉树叶子节点个数
思路:左右孩子都为空的节点为叶子节点

/**
 * 题目:用非递归算法获取二叉树叶子节点个数
 * @param root 二叉树根节点
 * @return 叶子节点的个数
 */
public static int getLeafNodeNum(BinaryTreeNode<Integer> root) {
    /* 根节点为空则返回0 */
    if (root == null) {
        return 0;
    }

    /* 计算二叉树叶子节点个数 */
    // 声明并初始化叶子节点个数
    int count = 0;
    // 声明并初始化出队元素
    BinaryTreeNode<Integer> temp = new BinaryTreeNode<Integer>();
    // 声明并初始化存储二叉树节点的队列
    LinkListQueue<BinaryTreeNode<Integer>> queue = new LinkListQueue<BinaryTreeNode<Integer>>();

    // 根节点先入队
    queue.enQueue(root);
    // 遍历队列直到为空
    while (!queue.isEmpty()) {
        // 获取出队元素
        temp = queue.deQueue();
        // 检查当前节点是否是叶子节点
        if ((temp.getLeft() == null) && (temp.getRight() == null)) {
            // 叶子节点个数自增
            count++;
        } else {
            // 如果当前节点的左孩子存在则入队
            if (temp.getLeft() != null) {
                queue.enQueue(temp.getLeft());
            }
            // 如果当前节点的右孩子存在则入队
            if (temp.getRight() != null) {
                queue.enQueue(temp.getRight());
            }
        }
    }
    return count;
}
题目:用非递归算法获取二叉树满节点个数
思路:左右孩子都存在的节点为满节点
代码与获取叶子节点相似,只需要将判断条件改为以下代码即可:

// 检查当前节点是否是满节点
if ((temp.getLeft() != null) && (temp.getRight() != null)) {
    // 叶子节点个数自增
    count++;
} 
题目:用非递归算法获取二叉树半节点个数
思路:仅有一个孩子存在的节点为半节点
代码与获取叶子节点相似,只需要将判断条件改为以下代码即可:

// 检查当前节点是否是半节点
if (((temp.getLeft() != null) && (temp.getRight() == null)) || ((temp.getRight() != null) && (temp.getLeft() == null))) {
    // 半节点个数自增
    count++;
} 

说明:完整代码,敬请参考本人github数据结构与算法(JAVA版),如有错误敬请指正!