Java实现二叉树

目录

一.树的基本概念

1.树是什么

2.树的名词概念

二.二叉树

1.概念

2.特殊的二叉树

2.1 完全二叉树

2.2 满二叉树

​编辑

3.二叉树的性质

三.二叉树的模拟实现

1.二叉树的存储

2.二叉树的遍历

2.1 前序遍历

2.2 中序遍历

2.3 后序遍历

3.树中节点的个数

4.叶子节点的个数

5.获取第K层节点的个数

6.获取二叉树的高度

7.检测值为value的元素是否存在


声明:结点和节点这两词都对,本文没有做区分,以下所说的节点和结点都是一个东西。

一.树的基本概念

1.树是什么

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。

因为其结构像一颗倒立的树,所以叫树。

树具有以下特点:

一个n个节点的树有 n-1 条边(每个节点上面都有一条边连着,只有根节点没有,所以是 n-1 );

有一个特殊的结点,称为根结点,根结点没有前驱结点;

子树之间不能有交集,每个子节点只有一个父节点;

树是递归定义的(重要)。

2.树的名词概念

结点度:一个结点含有子树的个数称为该结点的度,这个只针对某一个结点;

树度:一棵树中,所有结点度的最大值称为树的度;

叶子结点(终端结点):度为0的结点称为叶结点;

父节点(双亲结点):若一个结点含有子结点,则这个结点称为其子结点的父结点;

子节点(孩子结点):一个结点含有的子树的根结点称为该结点的子结点;

根结点:一棵树中,没有双亲结点的结点,最上面那一个;

结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推;

树的高度(深度):树中结点的最大层次;

分支结点(非终端结点):度不为0的结点;

兄弟结点:有相同父节点的结点;

堂兄弟结点:父节点在同一层的结点。注意不只是父节点是兄弟结点,在同一层都可以;

结点的祖先:从根到该结点所经分支上的所有结点;

子孙:以某结点为根的子树中任一结点都称为该结点的子孙;

森林:由m(m>=0)棵互不相交的树组成的集合称为森林。

二.二叉树

1.概念

二叉树是一种特殊的树,顾名思义,二叉树的父节点最多有两个子节点。二叉树的子树是有顺序的,一个是左子树,一个右子树。

2.特殊的二叉树

2.1 完全二叉树

完全二叉树是效率很高的数据结构。对于深度为K的,有 n 个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从0至n-1的结点一一对应时称之为完全二叉树。

2.2 满二叉树

满二叉树一种特殊的完全二叉树,每层结点都达到最大值,即除了根节点和叶子节点其他的节点的度都为2。如果一棵二叉树的层数为K,那么结点总数是2^{k}-1

3.二叉树的性质

3.1  若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有 2^{i-1}(i>0)个结点。

每一个父节点最多有两个子节点,父节点下一层的节点数的最大值就是父节点数的2倍。那么第 i 层其实就是第一层的2^{i-1}倍。

3.2  若规定只有根结点的二叉树的深度为1,则深度为K的二叉树的最大结点数是 2^{k}-1(k>=0)。

深度即为最大层数,假设这颗树是满二叉树,那么此时结点数最多,根据满二叉树的性质我们可得最大结点数是2^{k}-1

3.3  对任何一棵二叉树, 如果其叶结点个数为 n0, 度为2的非叶结点个数为 n2,则有n0=n2+1。

设 度数为1的非叶节点个数为n3,结点总数为n

n = n0 + n1 + n2   ------------结点总数

n - 1 = 0 * n0 + 1 * n1 + 2 * n2  ---------结点的边  

将两个式子联立可得:n0 = n2 + 1

3.4  具有n个结点的完全二叉树的深度k为 {log{}}^{n+1}上取整(log指的是log2)。

3.5  对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始编号,则对于序号为i 的结点有:

若i>0,双亲序号:(i-1)/2;i=0,i为根结点编号,无双亲结点;

若2i+1<n,左孩子序号:2i+1,否则无左孩子;

若2i+2<n,右孩子序号:2i+2,否则无右孩子。

三.二叉树的模拟实现

1.二叉树的存储

二叉树有两种存储方式:顺序表存储和链式存储,这里用的是链式存储。

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

e是某一种数据类型,看实际要存什么。

2.二叉树的遍历

二叉树的遍历大体分为四种:前序、中序、后序和层序。学过离散数学的应该很熟悉,这里不深入说了,只举一个例子。

前序遍历:FBADCEGIH        (根 -> 左子树 -> 右子树)

中序遍历:ABCDEFGHI        (左子树 -> 根 -> 右子树)

后序遍历:ACEDBHIGF        (左子树 -> 右子树 -> 根)

层序遍历:FBGADICEH        (逐层)

2.1 前序遍历

public void preOrder(BTNode root) {
        if(root==null){
            return ;
        }

        System.out.print(root.value+" ");
        preOrder(root.left);
        preOrder(root.right);
    }

利用的就是递归的思想。preOrder可以理解成应该打印函数,第一步打印当前节点,第二步去打印左子树的节点,第三步去打印右子树的节点。注意,递归是要有终止条件的,模拟一下,叶节点就没有左右子树了,所以到root==nul是就“往回走”了。

剩下的同理。

2.2 中序遍历

 public void inOrder(BTNode root) {
        if(root==null){
            return ;
        }

        inOrder(root.left);
        System.out.print(root.value+" ");
        inOrder(root.right);
    }

2.3 后序遍历

public void postOrder(BTNode root) {
        if(root==null){
            return ;
        }

        postOrder(root.left);
        postOrder(root.right);
        System.out.print(root.value+" ");
    }

3.树中节点的个数

 public int size(BTNode root) {
        if(root==null){
            return 0;
        }

        return size(root.left)+size(root.right)+1;
    }

也是递归实现,某一颗树的结点个数就是左子树结点的个数+右子树结点的个数+结点本身。这个公式就可以递归下去。终止条件就是“到底了”,没子树了。

4.叶子节点的个数

    public int n;
    public int getLeafNodeCount(BTNode root) {
        if(root==null){
            return 0;
        }

        if(root.left==null && root.right==null){
            n++;
        }

        getLeafNodeCount(root.left);

        getLeafNodeCount(root.right);
        return 0;
    }

步骤:判断当前节点是不是子节点,如果是就数量++,如果不是,就找它的左子节点是不是叶节点,然后找它的右子节点是不是叶节点。

5.获取第K层节点的个数

public int getKLevelNodeCount(BTNode root, int k) {
        if(root==null){
            return 0;
        }

        if(k==1){
            return 1;
        }

        return getKLevelNodeCount(root.left,k-1)+getKLevelNodeCount(root.right,k-1);
    }

6.获取二叉树的高度

    public int getHeight(BTNode root) {
        if(root==null){
            return 0;
        }

        return Math.max(getHeight(root.left),getHeight(root.right))+1;
    }

树的高度等于最大层数,找最大层数,加上1就是高度。

7.检测值为value的元素是否存在

    public BTNode find(BTNode root, int val) {
        if(root==null){
            return null;
        }

        if(root.value==val){
            return root;
        }else{
            find(root.left,val);
            find(root.right,val);
        }

        return null;
    }

步骤:首先,判断当前的节点的val是不是要找的。如果不是,找它的左子树有没有,然后找它的右子树有没有。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值