六、二叉树

1. 下面这个东西就叫做二叉树

在这里插入图片描述

  • 二叉树节点的代码:
class TreeNode{
    int key; // 键值
    TreeNode left; // 左孩子
    TreeNode right; // 右孩子
    TreeNode parent; // 父节点(有时需要)
    
    //构造器
    public TreeNode(int key){
        this.key = key;
        left = null;
        right = null;
        parent = null;
    }
}
  • 递归求二叉树的高度(即根节点到叶子节点的最长的长度)
public static int getHeight(TreeNode root){
    if(root == null) return 0;
    return Math.max(getHeight(root.left), getHeight(root.right)) + 1;
}

2. 前序遍历、中序遍历、后序遍历

2.1 前序遍历(中左右)

public static void preOrder(TreeNode root){
    if(root != null){
        System.out.println(root.key);// 中
        preOrder(root.left);// 左
        preOrder(root.right);// 右
    }
}

在这里插入图片描述

2.2 中序遍历(左中右)

public static void inOrder(TreeNode root){
    if(root != null){
        preOrder(root.left);// 左
        System.out.println(root.key);// 中
        preOrder(root.right);// 右
    }
}

在这里插入图片描述

2.3 后序遍历(左右中)

public static void postOrder(TreeNode root){
    if(root != null){
        preOrder(root.left);// 左
        preOrder(root.right);// 右
        System.out.println(root.key);// 中

    }
}

在这里插入图片描述

2.4 关于遍历的小知识

  • 前序遍历中序遍历能唯一确定一棵树;同理,后序遍历中序遍历也可以;但是前序遍历后续遍历却不行,下图就是一个反例。

在这里插入图片描述

3. 二叉搜索树

3.1 定义

  • 不等式:左孩子节点的值 ≤ 节点的值 ≤ 右孩子节点的值

在这里插入图片描述

3.2 二叉搜索树的判定

  • 大致思想:自顶向下遍历各个节点,一旦发现某个节点不符合搜索树的不等式,则该树不是搜索树,返回false。如果到达叶子节点依然没有返回false,则返回true。
  • 时间复杂度:O(n) (不是O(nlgn),PPT上的不对。不过无关紧要,这不是很重要。)
public static boolean isBST(TreeNode root){
    // 到达叶节点,返回
    if(root == null) return true;
    // 判断左子树的最大值是否大于根节点
    if (root.left != null && root.left.max() > root.key) return false;
    // 判断右子树的最小值是否小于根节点
    if (root.right != null && root.right.min() < root.key) return false;
	// 继续判定子节点
    return isBST(root.left) && isBST(root.right);
}

3.3 如何将二叉搜索树中的值按从小到大顺序输出?

  • 使用中序遍历(左中右):例如上面的二叉搜索树,中序遍历的输出为2,3,4,6,7,9,13,15,17,18,20。

3.4 在BST中查找某个元素

  • 3.4.1 使用循环(也叫迭代)
TreeNode search(int key) {
    // 从根节点开始搜索
    TreeNode cur = root;
    while (cur != null && cur.key != key) 
        // cur.key比key大,则往右搜索;比key小,则往左搜索
        cur = cur.key > key ? cur.left:cur.right; 
    return cur;
}
3.4.2 使用递归
TreeNode search(TreeNode root, int key){
    if (root == null || root.key == key)
        return root;
    // cur.key比key大,则往右搜索;比key小,则往左搜索
    return root.key > key ? search(root.left, key):search(root.right, key);
}

3.5 查找BST中的最大最小值

    public TreeNode maximum (TreeNode node) {
        // 一路向右
        while (node != null && node.right != null) {
            node = node.right;
        }
        return node;
    }

    public TreeNode minimum (TreeNode node) {
        // 一路向左
        while (node != null && node.left !=null) {
            node = node.left;
        }
        return  node;
    }

3.6 前驱后继

3.6.1 后继
  • 后继:比x大的最小的数,称为x的后继。例如,下图中,6的后继是7。

在这里插入图片描述

    TreeNode successor(TreeNode node) {
        // 当该节点有右孩子
        if (node.right != null) {
            return minimum(node.right);
        }
        
        // 当该节点没有右孩子,这种情况有一定难度。重要程度:一般
        TreeNode y = node.parent;
        while (y != null && node == y.right) {
            node = y;
            y = y.parent;
        }
        return y;
    }
3.6.2 前驱
  • 前驱:比x小的最大的数,称为x的前驱。例如,下图中,6的前驱是3。

在这里插入图片描述

	TreeNode predecessor(TreeNode node) {
        // 当该节点有左孩子
        if (node.left != null) {
            return maximum(node.left);
        }

        // 当该节点没有左孩子,这种情况有一定难度。重要程度:一般
        TreeNode y = node.parent;
        while (y != null && node == y.left) {
            node = y;
            y = y.parent;
        }
        return y;
	}
3.7 插入元素
    public void insert(TreeNode node) {
        TreeNode y = null;
        TreeNode x = this.root;
        // 寻找一个节点,使得node可以插在这个节点后面
        while (x != null) {
            y = x;
            x = node.key < x.key ? x.left:x.right;
        }
        node.parent = y;
        // 如果 y == null,那么这是个空树,直接把node设成根节点
        if (y == null)
            this.root = node;
        // 插左边
        else if (node.key < y.key)
            y.left = node;
        else
        // 插右边
            y.right = node;
    }
3.8 删除元素
  • 放心不会考的,太复杂了
    public TreeNode deleteNode(TreeNode root, int key) {
        if (root == null) {
            return null;
        }
        if (key < root.key) {
            // 待删除节点在左子树中
            root.left = deleteNode(root.left, key);
            return root;
        } else if (key > root.key) {
            // 待删除节点在右子树中
            root.right = deleteNode(root.right, key);
            return root;
        } else {
            // key == root.val,root 为待删除节点
            if (root.left == null) {
                // 返回右子树作为新的根
                return root.right;
            } else if (root.right == null) {
                // 返回左子树作为新的根
                return root.left;
            } else {
                // 左右子树都存在,返回后继作为新的根
                TreeNode successor = successor(root);
                successor.right = predecessor(root.right);
                successor.left = root.left;
                return successor;
            }
        }
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值