跳到主要内容

18、数据结构与算法 - 实战:二叉树1

题目:查找二叉树中最大元素
思路1:利用递归思想,分别查找到左子树中最大元素和右子树中最大元素,然后将它们与根节点的值进行比较。

/**
 * 查找二叉树中最大元素
 * @param root 二叉树根节点
 * @return 二叉树中最大元素
 */
public static int findMax(BinaryTreeNode<Integer> root) {
    int max = Integer.MIN_VALUE;
    int root_val = 0;
    int left_val = 0;
    int right_val = 0;
    if (root != null) {
        root_val = root.getData();
        left_val = findMax(root.getLeft());
        right_val = findMax(root.getRight());
        // 3个值进行比较
        if (left_val > right_val) {
            max = left_val;
        } else {
            max = right_val;
        }
        if (root_val > max) {
            max = root_val;
        }
    }
    return max;
}
思路2:利用层序遍历,在节点出队时观察其数据值是否为最大值

/**
 * 用非递归的方法查找二叉树中最大元素
 * @param root 二叉树根节点
 * @return 二叉树中最大元素
 */
public static int findMaxUsingLevelOrder(BinaryTreeNode<Integer> root) {
    int max = Integer.MIN_VALUE;
    BinaryTreeNode<Integer> temp;
    LinkListQueue<BinaryTreeNode<Integer>> queue = new LinkListQueue<BinaryTreeNode<Integer>>();

    // 根节点先入队
    queue.enQueue(root);
    // 队列不为空则遍历
    while (!queue.isEmpty()) {
        // 获取出队元素
        temp = queue.deQueue();
        // 判断最大值
        if (temp.getData() > max) {
            max = temp.getData();
        }
        // 出队节点的左子树不为空,则左子树入队
        if (temp.getLeft() != null) {
            queue.enQueue(temp.getLeft());
        }
        // 出队节点的右子树不为空,则右子树入队
        if (temp.getRight() != null) {
            queue.enQueue(temp.getRight());
        }
    }
    return max;
}
题目:搜索二叉树中某个元素
思路1:对于给定的二叉树,如果发现树中某个节点的数据值与搜索的元素值相同,返回true。递归的从树根节点向下,比较左子树与右子树各个节点的值。

/**
 * 题目:搜索二叉树中某个元素
 * @param root 二叉树根节点
 * @param data 目标数据值
 * @return true 存在该元素 false 不存在该元素
 */
public static boolean hasData(BinaryTreeNode<Integer> root, int data) {
    boolean temp = false;
    // 二叉树为空,说明数据未找到,返回false
    if (root == null) {
        return false;
    } else {
        // 判断当前节点的值是否等于目标数据值
        if (root.getData() == data) {
            return true;
        } else {
            // 判断左子树是否包含该元素
            temp = hasData(root.getLeft(), data);
            // 如果左子树不包含该元素,查找右子树
            if (!temp) {
                temp = hasData(root.getRight(), data);
            }
        }
    }
    return temp;
}
思路2:层序遍历

/**
 * 题目:用非递归方法搜索二叉树中某个元素
 * @param root 二叉树根节点
 * @param data 目标数据值
 * @return true 存在该元素 false 不存在该元素
 */
public static boolean hasDataByLevelOrder(BinaryTreeNode<Integer> root, int data) {
    BinaryTreeNode<Integer> temp = new BinaryTreeNode<Integer>();
    LinkListQueue<BinaryTreeNode<Integer>> queue = new LinkListQueue<BinaryTreeNode<Integer>>();
    // 二叉树为空,说明数据未找到,返回false
    if (root == null) {
        return false;
    } 
    // 根节点入队
    queue.enQueue(root);
    // 当队列不为空则遍历
    while (!queue.isEmpty()) {
        // 获取出队元素
        temp = queue.deQueue();
        // 判断当前节点是否是目标元素
        if (temp.getData() == data) {
            return true;
        }
        // 左子树不为空时入队列
        if (temp.getLeft() != null) {
            queue.enQueue(temp.getLeft());
        }
        // 左子树不为空时入队列
        if (temp.getRight() != null) {
            queue.enQueue(temp.getRight());
        }
    }
    return false;
}
题目:向二叉树插入一个元素
思路:因为给定的是二叉树,所以能在任意位置插入元素。为了插入元素,可以使用层序遍历找到一个左孩子或右孩子为空的节点,然后插入该元素。

/**
 * 题目:向二叉树插入一个元素
 * @param root 二叉树的根节点
 * @param data 需要插入的元素
 * @return 插入新元素后的根节点
 */
public static BinaryTreeNode<Integer> insert(BinaryTreeNode<Integer> root, int data) {
    // 创建新节点
    BinaryTreeNode<Integer> newNode = new BinaryTreeNode<Integer>(data);
    // 二叉树为空则设置根节点并返回
    if (root == null) {
        root = newNode;
        return root;
    }

    // 出队元素
    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.setLeft(newNode);
            return root;
        } else {
            queue.enQueue(temp.getLeft());
        }

        // 检查当前节点右孩子是否为空
        if (temp.getRight() == null) {
            temp.setRight(newNode);
            return root;
        } else {
            queue.enQueue(temp.getRight());
        }
    }
    return null;
}
题目:获取二叉树节点个数
思路1:递归计算左子树和右子树的大小,再加一

/**
 * 题目:获取二叉树节点个数
 * @param root 二叉树根节点
 * @return 二叉树节点数
 */
public static int size(BinaryTreeNode<Integer> root) {
    if (root == null) {
        return 0;
    } else {
        return (size(root.getLeft()) + 1 + size(root.getRight()));
    }
}
思路2:利用层序遍历,有元素出队时节点个数加一

/**
 * 题目:非递归获取二叉树节点个数
 * @param root 二叉树根节点
 * @return 二叉树节点数
 */
public static int sizeByLevelOrder(BinaryTreeNode<Integer> root) {
    if (root == null) {
        return 0;
    }
    // 出队元素
    BinaryTreeNode<Integer> temp = new BinaryTreeNode<Integer>();
    // 创建存储二叉树节点的队列
    LinkListQueue<BinaryTreeNode<Integer>> queue = new LinkListQueue<BinaryTreeNode<Integer>>();
    // 根节点入队
    queue.enQueue(root);
    // 计数
    int count = 0;
    // 队列不为空则遍历
    while (!queue.isEmpty()) {
        // 获取出队元素
        temp = queue.deQueue();
        // 计数加一
        count++;
        // 当前节点左子树不为空则入队
        if (temp.getLeft() != null) {
            queue.enQueue(temp.getLeft());
        }
        // 当前节点右子树不为空则入队
        if (temp.getRight() != null) {
            queue.enQueue(temp.getRight());
        }
    }
    return count;
}
题目:逆向逐层输出树中的元素
思路:采用层序遍历,将数据先存入队列,然后出队存入栈中,最后再出栈即可
    例如下图所示的二叉树逆向逐层输出顺序为:4 5 6 7 2 3 1
                           二叉树
                             1
                            / \
                           2   3
                          / \ / \ 
                         4  5 6  7

/**
 * 题目:逆向逐层输出树中的元素
 * @param root 二叉树根节点
 */
public static void printLevelInReverse(BinaryTreeNode<Integer> root) {
    // 如果根节点为空,即二叉树本来就不存在
    if (root == null) {
        return;
    }

    // 存储出队元素
    BinaryTreeNode<Integer> temp = new BinaryTreeNode<Integer>();
    // 创建存储二叉树节点的队列
    LinkListQueue<BinaryTreeNode<Integer>> queue = new LinkListQueue<BinaryTreeNode<Integer>>();
    // 创建存储出队元素的栈
    LinkedListStack<BinaryTreeNode<Integer>> stack = new LinkedListStack<BinaryTreeNode<Integer>>();

    // 根节点最先入队
    queue.enQueue(root);

    // 队列不为空则遍历
    while (!queue.isEmpty()) {
        // 获取出队元素
        temp = queue.deQueue();
        // 将出队元素入栈
        stack.push(temp);
        // 右子树先入队
        if (temp.getRight() != null) {
            queue.enQueue(temp.getRight());
        }
        // 左子树后入队
        if (temp.getLeft() != null) {
            queue.enQueue(temp.getLeft());
        }
    }

    // 输出结果
    System.out.print("逐层逆向输出:");
    while (!stack.isEmpty()) {
        System.out.print(stack.pop().getData() + " ");
    }
}

说明:完整代码以及对应的测试用例已经提交到我的github上,如有错误敬请指正
https://github.com/Lining531309997/DataStructure