二叉树的深度理解

到难点了,个人认为初阶数据结构最难的点就在于二叉树,所以我尽量写的详细,清楚一些

文章目录

    • 概要
    • 二叉树(重要)
    • 二叉树的性质:
    • 遍历
    • 技术细节
    • 小结
  • 十一、其他文章接口
    • 1.String方法(重要,对于操作字符串有巨大的帮助)
    • 2.java常用的接口及其方法(包含拷贝,比较,排序,构造器)
    • 3.初阶数据结构
      • 3.1 顺序表:ArrayList
      • 3.2 链表:LinkedList
      • 3.3 栈:Stack
      • 3.4 队列:Queue
      • 3.5 二叉树:Tree
      • 3.6 优先级队列:PriorityQueue(堆排序)
      • 3.7 Map和Set
    • 4. 排序(7种方式)
      • 4.1 插入排序(两种)
      • 4.2 选择排序(两种)
      • 4.3 快速排序
      • 4.4 堆排序
      • 4.5 归并排序
    • 5.多线程
    • 6.网络编程
    • 7.HTML
    • 8.数据库Mysql

概要

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。这种结构类似于一颗大树的成长。首先是一个结点,树成长了,形成了几个叶子,而这几个叶子也将成为这个枝干的结点。只不过这是自然界的树,在计算机数据结构中,这颗树是倒着这的。

这个图树一个比较特殊的树,名字叫二叉树
二叉树的深度理解_第1张图片
这个机构我先提出几个问题:

  1. 如何获取到我想要的元素
  2. 我在添加元素时该如去做
  3. 如何通过根结点找到子结点的位置。

答:

  1. 通过遍历获取,怎么遍历?一般的循环遍历肯定不适合这个结构 ,那么就需要通过递归来遍历整个数据结构
  2. 通过类似于LinkedList(链表)结构去添加元素
  3. 也通过记录字节点的位置,寻找子叶结点。

补充几个概念:(重要)
二叉树的深度理解_第2张图片

  1. 结点的度:一个结点含有子树的个数称为该结点的度; 如上图:A的度为6
  2. 树的度:一棵树中,所有结点度的最大值称为树的度; 如上图:树的度为6
  3. 叶子结点或终端结点:度为0的结点称为叶结点; 如上图:B、C、H、I…等节点为叶结点
  4. 双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点; 如上图:A是B的父结点
  5. 孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点; 如上图:B是A的孩子结点
  6. 根结点:一棵树中,没有双亲结点的结点;如上图:A
  7. 结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推
  8. 树的高度或深度:树中结点的最大层次; 如上图:树的高度为4

二叉树(重要)

规定:

  1. 二叉树不存在度大于2的结点
  2. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

二叉树的深度理解_第3张图片
二叉树的深度理解_第4张图片

二叉树又分为。满二叉树和完全二叉树

满二叉树:及每个结点的子结点个数都为2,也就是满的

百度定义:
满二叉树: 一棵二叉树,如果每层的结点数都达到最大值,则这棵二叉树就是满二叉树。也就是说,如果一棵二叉树的层数为K,且结点总数是 2^k-1,则它就是满二叉树。
二叉树的深度理解_第5张图片
———————————————————————————————————————————
完全二叉树:具有二叉树性质的,最差满足左树的二叉树。也就是说,无需去理会是否同时具有左树和右树的情况(满足这个情况的其实是满二叉树),但必须满足左树存在的情况。

百度定义:
完全二叉树: 完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从0至n-1的结点一一对应时称之为完全二叉树。
二叉树的深度理解_第6张图片

注意:
是满二叉树是一种特殊的完全二叉树。

二叉树的性质:

  1. 若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1) (i>0)个结点
    二叉树的深度理解_第7张图片

  2. 若规定只有根结点的二叉树的深度为1,则深度为K的二叉树的最大结点数是2^k-1 (k>=0)
    二叉树的深度理解_第8张图片

  3. 对任何一棵二叉树, 如果其叶结点个数为 n0, 度为2的非叶结点个数为 n2,则有n0=n2+1
    二叉树的深度理解_第9张图片

  4. 具有n个结点的完全二叉树的深度(层数)k为log2(n+1) 上取整
    二叉树的深度理解_第10张图片

  5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始编号,则对于序号为i的结点有:
    若i>0,双亲序号:(i-1)/2;i=0,i为根结点编号,无双亲结点
    (1):若2i+1i+1,否则无左孩子
    (2):若2i+2i+2,否则无右孩子

二叉树的深度理解_第11张图片
二叉树的存储结构分为:顺序存储(下面回仔细讲解(堆排序))和类似于链表(这里将实现)的链式存储

class Node {
	int val; // 数据域
	Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
	Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
}

二叉树的深度理解_第12张图片

遍历

双叉树的遍历分为3种: 前序遍历,中序遍历,后序遍历

前序遍历:访问根结点—>根的左子树—>根的右子树

    static class TreeNode {
        public char val;
        public TreeNode left;//左孩子的引用
        public TreeNode right;//右孩子的引用
        public TreeNode(char val) {
            this.val = val;
        }
    }
    /**
     * 创建一棵二叉树 返回这棵树的根节点
     *
     * @return
     */
    public TreeNode root=null;
    
    public TreeNode createTree() {
        TreeNode root=null;
        return root;
    }
    // 前序遍历
    public void preOrder(TreeNode root) {
        if (root==null) {
            return;
        }
        //先访问根结点的数据
        System.out.println(root.val);
        //在访问左子字节点的数据
        preOrder(root.left);
        //最后访问右子结点的数据
        preOrder(root.right);;
    }

前序遍历

中序遍历:根的左子树—>根节点—>根的右子树。


static class TreeNode {
        public char val;
        public TreeNode left;//左孩子的引用
        public TreeNode right;//右孩子的引用
        public TreeNode(char val) {
            this.val = val;
        }
    }
    /**
     * 创建一棵二叉树 返回这棵树的根节点
     *
     * @return
     */
    public TreeNode root=null;
    
    public TreeNode createTree() {
        TreeNode root=null;
        return root;
    }
    //中序遍历
 void inOrder(TreeNode root) {
        if (root==null) {
            return;
        }
        //先遍历左字节点
        inOrder(root.left);
        //再遍历根节点
        System.out.println(root.val);
        //最后遍历右结点
        inOrder(root.right);;
    }

中序遍历

后序遍历:根的左子树—>根的右子树—>根节点。


static class TreeNode {
        public char val;
        public TreeNode left;//左孩子的引用
        public TreeNode right;//右孩子的引用
        public TreeNode(char val) {
            this.val = val;
        }
    }
    /**
     * 创建一棵二叉树 返回这棵树的根节点
     *
     * @return
     */
    public TreeNode root=null;
    
    public TreeNode createTree() {
        TreeNode root=null;
        return root;
    }
	// 后序遍历
    void postOrder(TreeNode root) {
        if (root==null) {
            return;
        }
        //先访问左树的数据
        postOrder(root.left);
        //再访问右树的数据
        postOrder(root.right);
        //最后访问根的数据
        System.out.println(root.val);
    }

后序遍历

层序遍历:从左往右依次遍历

  //层序遍历
    public void levelOrder(TreeNode root){
        if (root==null){
            return;
        }
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()){
            TreeNode cur=queue.poll();
            System.out.print(cur.val+"");
            if (cur.left!=null){
                queue.offer(cur.left);
            }
            if (cur.right!=null){
                queue.offer(cur.right);
            }
        }
    }

技术细节

到了这里,其实大家对于二叉树的结构已经较为了解了,接下来,大家可以尝试书写一下我所实现的功能。真没心力去做视频了。等我回复一点血,在讲解下面的代码。求求了。。。。,我好像挖了不少的坑。。。。

public class TestBinaryTree {
    static class TreeNode{
        public char val;//数据域
        public TreeNode left;//左孩子
        public TreeNode right;//右孩子
        public TreeNode(char val){
            this.val=val;
        }

    }
   public TreeNode root;//二叉树的根节点
    public void createTree(){

    }
    //前序遍历
    public void preOrder(TreeNode root){
        if (root==null){
            return;
        }
        System.out.println(root.val+"");
        preOrder(root.left);
        preOrder(root.right);
    }
    public List<Character> preorderTraversal(TreeNode root) {
        List<Character> ret=new ArrayList<>();
        if (root==null){
            return null;
        }
            ret.add(root.val);
            List<Character> leftret= preorderTraversal(root.left);
            leftret.addAll(leftret);
            List<Character> rightret= preorderTraversal(root.left);
            leftret.addAll(rightret);
            return ret;
    }


    // 中序遍历
  public  void inOrder(TreeNode root){
      if (root==null){
          return;
      }
      inOrder(root.left);
      System.out.println(root.val+"");
      inOrder(root.right);
  }
    // 后序遍历
    public void postOrder(TreeNode root){
        if (root==null){
            return;
        }
        postOrder(root.left);
        postOrder(root.right);
        System.out.println(root.val+"");
    }

    // 获取树中节点的个数
    public int size(TreeNode root){
        if (root==null){
            return 0;
        }
        int leftSize=size(root.left);
        int rightSize=size(root.right);



        return leftSize+rightSize+1;
    }
    // 获取叶子节点的个数
    public int getLeafNodeCount(TreeNode root){
            if (root==null){
                return 0;
            }
            if (root.left==null&&root.right==null){
                return 1;
            }
            int leftroot=getLeafNodeCount(root.left);
            int rightroot=getLeafNodeCount(root.right);
            return leftroot+rightroot;



    }
    // 子问题思路-求叶子结点个数
	// 获取第K层节点的个数
    public int getKLevelNodeCount(TreeNode root,int k){
            if (root==null){
                return 0;

            }
            if (k==1){
                return 1;
            }
            int leftSzie=   getKLevelNodeCount(root.left,k-1);
            int rightSize=  getKLevelNodeCount(root.right,k-1);
            return leftSzie+rightSize;

    }
    // 获取二叉树的高度
    public int getHeight(TreeNode root){
        if (root==null){
            return 0;
        }
        int rightSzie =getHeight(root.right);
        int leftSzie=getHeight(root.left);
        if (rightSzie>=leftSzie){
            return rightSzie+1;
        }else {
            return leftSzie+1;
        }
    }
    // 检测值为value的元素是否存在
    public TreeNode find(TreeNode root, int val){
        if (root==null){
            return null;
        }
        if (root.val==val){
            return root;
        }
        TreeNode leftTree=find(root.left, val);
        if (leftTree!=null){
            return leftTree;
        }
        TreeNode rightTree=find(root.right, val);
        if (rightTree!=null){
            return rightTree;
        }
        return null;

    }
    //层序遍历
    public void levelOrder(TreeNode root){
        if (root==null){
            return;
        }
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()){
            TreeNode cur=queue.poll();
            System.out.print(cur.val+"");
            if (cur.left!=null){
                queue.offer(cur.left);
            }
            if (cur.right!=null){
                queue.offer(cur.right);
            }
        }
    }
    // 判断一棵树是不是完全二叉树
    public boolean isCompleteTree(TreeNode root){
        if (root==null){
            return false;
        }
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()){
            TreeNode cur= queue.poll();
            if (cur!=null){
                queue.offer(cur.left);
                queue.offer(cur.right);
            }else {
                break;
            }
        }

        while (!queue.isEmpty()){
            TreeNode tmp=queue.poll();
            if (tmp!=null){
                return false;
            }
        }
        return true;
    }


}

小结

  1. 树这种结构对于计算机来说极为重要,而这篇文章所讲的其实连毛都算不上,主要就是让大家了解了一下树这种结构
  2. 理解上述代码,对于绝大部分的算法都会用到,别问,问就是在牛客上刷到了
  3. 重点理解遍历就可。大家肯定都比我聪明。下面的代码我都理解了好久。
  4. 重点要关注一下树的叶子,和高度的求法。
  5. 求求了,给个赞,我图画的很多很多。视频制作真的很累。。。

十一、其他文章接口

1.String方法(重要,对于操作字符串有巨大的帮助)

文章链接

2.java常用的接口及其方法(包含拷贝,比较,排序,构造器)

文章链接

3.初阶数据结构

3.1 顺序表:ArrayList

文章链接

3.2 链表:LinkedList

文章链接

3.3 栈:Stack

文章链接

3.4 队列:Queue

文章链接

3.5 二叉树:Tree

文章链接

3.6 优先级队列:PriorityQueue(堆排序)

文章链接

3.7 Map和Set

HashMap和HashSet,TreeMap和TreeSet
文章链接

4. 排序(7种方式)

4.1 插入排序(两种)

4.2 选择排序(两种)

4.3 快速排序

4.4 堆排序

里面有堆排序的实现和逻辑
文章链接

4.5 归并排序

5.多线程

文章链接

6.网络编程

7.HTML

8.数据库Mysql

文章链接

你可能感兴趣的:(java,数据结构,算法,java)