四、二叉树基本操作

🚀 一、树形结构

🌟 1.1 什么是树?

==此处添加树形结构图==
树形结构是一种非线性的数据结构,它有以下特点:

  • 有一个特殊的节点:根节点,根节点没有前驱节点。
  • 除根节点外,其余节点被分成 M(M > 0)个互不相交的集合,其中每一个集合又是一颗与树类似的子树。
  • 树是递归定义的。

🌟 1. 2 重要概念

  1. 节点的度:一个节点含有的子树的个数。
  2. 树的度:一棵树中,最大的节点的度称为树的度。
  3. 叶子节点:度为 0 的节点称为叶子节点。
  4. 双亲节点或父节点:若一个节点含有字节点,则这个节点称为它的子节点的父节点。
  5. 子节点:一个节点含有的子树的根节点为该节点的子节点。
  6. 节点的层次:从根节点开始定义,根节点为第一层,以此类推。
  7. 树的深度:树中节点的最大层次。

🚀 二、二叉树

==二叉树图片==

🌟 2.1 概念

一棵二叉树是节点的有限集合,该集合或为空,或为一个根节点加上两颗分别称为左子树和右子树的二叉树组成。

二叉树的特点:

  • 每个节点最多有两颗子树,二叉树不存在度大于 2 的节点。
  • 二叉树的子树有左右之分,不能颠倒,因为二叉树是有序树。

🌟 2.2 两种特殊二叉树

  1. 满二叉树:一个二叉树,每层的节点数都达到最大值,则这个树就是满二叉树。即如果一个二叉树的层数为 K ,且节点总数为 2^K - 1 ,则它就是满二叉树。
  2. 完全二叉树:完全二叉树是一种效率很高的数据结构。对于深度为 K 的,有 n 个节点的二叉树,当且仅当其每一个节点都与深度为 K 的满二叉树中编号 1 到 n 的节点的位置一一对应时才称为完全二叉树。完全二叉树的节点按下标依次存放且连续。满二叉树是特殊的完全二叉树。

在这里插入图片描述

🌟 2.3 二叉树的性质(重要)

  1. 若规定根节点层数为 1,则一棵非空二叉树的第 i 层上最多有 2^(i-1) 个节点
  2. 若规定只有根节点的二叉树的深度为 1,则深度为 K 的二叉树的最大节点数是 2^K - 1
  3. 对任一棵二叉树,如果其叶节点个数为 n0 ,度为 2 的非叶节点个数为 n2 ,则有 n0 = n2 + 1
  4. 具有 n 个节点的二叉树的深度 K 为 log( n+1 ) (以 2 为底)向上取整。
  5. 对于 n 个节点的完全二叉树按照从上至下从左至右的顺序对所有节点从 0 开始编号,则对于序号为 i 的节点有:
    • 若 i > 0 ,则父节点为 ( i-1 ) / 2。否则无父节点。
    • 若 2i +1 < n ,则左孩子为 2i + 1。
    • 若 2i + 2 < n,则右孩子为 2i + 2。

🌟 2.4 二叉树的存储

二叉树的存储结构分为顺序存储和链式存储。

  • 堆主要采用顺序结构存储。
  • 二叉树主要采用链式结构存储。

二叉树的链式存储是通过一个个的节点引用起来的,常见的有 孩子兄弟表示法 和 孩子双亲表示法。

// 链式结构下二叉树节点
// 孩子表示法
class Node {
	int val;	// 存储的数据
	Node left;	// 左孩子的引用
	Node right;	// 右孩子的引用
}

// 孩子双亲表示法
// AVL树、B-树、红黑树等树形结构会用到这种方法。
class Node{
	int val;	// 存储的数据
	Node left;	// 左孩子的引用
	Node right;	// 右孩子的引用
	Node parent;// 当前节点的根节点
}

🚀 三、二叉树的基本操作

🌟 3.1 构建二叉树说明

在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。先在下面手动快速创建一棵简单二叉树。

/**
 *  先创建一棵二叉树
 */
public TreeNode createTree(){
    TreeNode root = new TreeNode('A');
    TreeNode B = new TreeNode('B');
    TreeNode C = new TreeNode('C');
    TreeNode D = new TreeNode('D');
    TreeNode E = new TreeNode('E');
    TreeNode F = new TreeNode('F');
    TreeNode G = new TreeNode('G');
    TreeNode H = new TreeNode('H');
    
    root.left = B;
    root.right = C;
    B.left = D;
    B.right = E;
    C.left = F;
    C.right = G;
    E.right = H;
    
    return root;
}

上述代码并不是创建二叉树的真正方式,只是为了方便学习,快速搭建出来的。

🌟 3.2 二叉树的遍历

3.2.1 前中后序遍历

二叉树的遍历指沿着某条搜索路线,依次对树中每个节点做且仅做一次访问。遍历是二叉树最重要的操作之一。 二叉树的遍历主要有以下几种:

  1. 前序遍历:根节点 => 根的左子树 => 根的右子树
  2. 中序遍历:根的左子树 => 根节点 => 根的右子树
  3. 后序遍历:根的左子树 => 根的右子树 => 根节点
    在这里插入图片描述
/**
 *  前序遍历
 */
public void preOrder(TreeNode root){
    if(root == null){
        return ;
    }
    System.out.print(root.val + " ");
    preOrder(root.left);
    preOrder(root.right);
}
/**
 * 中序遍历
 * @param root
 */
public void inOrder(TreeNode root){
    if(root == null){
        return ;
    }
    inOrder(root.left);
    System.out.print(root.val + " ");
    inOrder(root.right);
}
/**
 * 后序遍历
 * @param root
 */
public void postOrder(TreeNode root){
    if(root == null){
        return ;
    }
    postOrder(root.left);
    postOrder(root.right);
    System.out.print(root.val + " ");
}

在这里插入图片描述

3.2.2 二叉树的层序遍历

设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
在这里插入图片描述

/**
 * 二叉树的层序遍历
 * 需要使用到 队列 的数据结构
 *
 * @param root
 */
public void levelOrder(TreeNode root){
    // 先创建一个队列,并把根节点放入队列
    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);
    // 循环条件是,队列里还有元素,即层序遍历还未完成。
    while(!queue.isEmpty()){
        // 弹出队列头节点,
        TreeNode top = queue.poll();
        System.out.print(top.val + " ");
        
        // 如果该节点的左子节点不为空,入队列 
        if(top.left != null){
            queue.offer(top.left);
        }
        // 如果该节点的右子节点不为空,入队列 
        if(top.right != null){
            queue.offer(top.right);
        }
    }
}

在这里插入图片描述

🌟 3.3 二叉树的基本操作

  1. 获取节点总数。
  2. 获取叶子节点总数
  3. 求第 K 层节点总数
  4. 获取二叉树高度
  5. 二叉树查找元素
/**
 *  遍历思路,获取节点个数
 */
static int size = 0;
public void getSize1(TreeNode root){
    if(root == null){
        return;
    }
    size++;
    getSize1(root.left);
    getSize1(root.right);
}

/**
 *  子问题思路,获取节点个数
 * @param root
 * @return
 */
public int getSize2(TreeNode root){
    if(root == null){
        return 0;
    }
    return getSize2(root.left) + getSize2(root.right) + 1;
}


/**
 * 遍历思路,求叶子节点个数
 */
static int leafSize = 0;
public void getLeafSize1(TreeNode root){
    if(root == null){
        return;
    }
    if(root.left == null && root.right == null){
        leafSize++;
    }
    getLeafSize1(root.left);
    getLeafSize1(root.right);
}

/**
 * 子问题思路,获取叶子节点个数
 * @param root
 * @return
 */
public int getLeafSize2(TreeNode root){
    if(root == null){
        return 0;
    }
    if(root.left == null && root.right==null){
        return 1;
    }
    return getLeafSize2(root.left) + getLeafSize2(root.right);
}


/**
 *  求第 K 层节点总数,子问题思路
 * @param root
 * @return
 */
public int getKlevelSize(TreeNode root, int k){
    if(root == null){
        return 0;
    }
    if(k == 1){
        return 1;
    }
    return getKlevelSize(root.left,k-1) + getKlevelSize(root.right,k-1);
}


/**
 * 获取二叉树高度
 *
 * @param root
 * @return
 */
public int getHeight(TreeNode root){
    if(root == null){
        return 0;
    }
    return Math.max(getHeight(root.left),getHeight(root.right))+1;
}


/**
 * 查找元素,根 => 左 => 右 的顺序进行查找
 * @param root
 * @param val
 * @return
 */
public TreeNode find(TreeNode root, char val){
    if(root == null){
        return null;
    }
    if(root.val == val){
        return root;
    }
    return find(root.left,val) == null ? find(root.right,val) : find(root.left,val);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值