数据结构——二叉树

1.树的结构

1.1树的概念

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
(1)有一个特殊的结点,称为根结点,根结点没有前驱结点
(2)除根结点外,其余结点被分成M(M > 0)个互不相交的集合T1、T2、…、Tm,其中每一个集 合Ti (1 <= i <=m) 又是一棵与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个()或多 个后继
(3)树是递归定义的。
在这里插入图片描述
1.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
  9. 非终端结点或分支结点:度不为0的结点; 如上图:D、E、F、G…等节点为分支结点
  10. 兄弟结点:具有相同父结点的结点互称为兄弟结点; 如上图:B、C是兄弟结点
  11. 堂兄弟结点:双亲在同一层的结点互为堂兄弟;如上图:H、I互为兄弟结点
  12. 结点的祖先:从根到该结点所经分支上的所有结点;如上图:A是所有结点的祖先
  13. 子孙:以某结点为根的子树中任一结点都称为该结点的子孙。如上图:所有结点都是A的子孙
  14. 森林:由m(m>=0)棵互不相交的树组成的集合称为森林

2.二叉树

2.1概念

一棵二叉树是结点的一个有限集合,该集合:

  1. 或者为空
  2. 或者是由一个根节点加上两棵别称为左子树和右子树的二叉树组成。
    在这里插入图片描述
    从上图可以看出:
  3. 二叉树不存在度大于2的结点
  4. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

3.对二叉树的操作

1.自定义一个二叉树。

对于一个二叉树的结构,包含左节点的引用,以及右节点的引用,以及存储的key值,我们做出如下代码定义一个二叉树

public class MyTree {
    static class myTree{
        public myTree left;
        public myTree right;
        public int val;

        public myTree(int val) {
            this.val = val;
        }
    }

    public myTree root;
}

如上代码,定义了一个可以存储int类型数据的二叉树,并提供了一个构造方法,用来初始化树。此时呢树还缺少其他操作,例如插入操作,删除操作,获取操作等。我们一个一个进行分析。

4.二叉树的遍历

4.1前序遍历

对于前序遍历其思想我们可以看下图:
在这里插入图片描述
(1)B,C相当于A节点的左右子树
(2)前序遍历的思路就是先打印根节点,在打印左节点,最后打印右节点
那么我的思路就是,先打印A节点后,我们去打印左子树,左子树也要满足前序遍历思想,此时,应该打印B,
B打印完成后,打印其左节点,再去打印其右节点,那么此时,根节点和左树打印完成,打印右树,右树同样得满足前序遍历规则,先打印C,在打印F,最后打印G。

根据上述得思路我们可以得到以下的代码:

    //前序遍历
    public void preOrder(myTree root){
        if (root == null){
            return;
        }
        System.out.println(root.val + " ");
        preOrder(root.left);
        preOrder(root.right);
    }

4.2中序遍历

中序遍历的思想就是,先打印左子树,在打印根节点,最后打印右子树,只有当左子树打印完成时才可以打印根节点,这就使得打印出的二叉树顺序,根节点在左子树和右子树的中间,一下就是中序遍历。

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

4.3后序遍历

完成了前序遍历和中序遍历,对于后序遍历,我们不难看出,区分这三种打印顺序最主要的是根节点的打印时机,后序遍历打印根节点在最后,也就是造成根节点永远在最后,以下就是后续遍历的代码:

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

4.4层序遍历

层序遍历,我们来看下图:
在这里插入图片描述
他的层序遍历结果为:A B C D E F G 。先打印第一层,在打印第二层,以此类推,我门可以借助队列的“先进先出”这一特点来完成层序遍历。
第一步,我们先将A节点放入队列中,我们直接将A出队列
第二步,将A节点的左节点放入队列,再将右节点放入队列,
第三步,将B节点出队列,将B节点的左节点放入队列,右节点放入队列
到了第三步,大家有没有发现,队列中,总是每一层的最左端先出队列,同时将这个节点的左右节点,放到了队尾,当上一层全部出队列,下一层也已经从左至右的存放在队列当中,我们只需要判断队列是否为空,如果不为空继续出队列,

//层序遍历
    public List<Integer> levelOrder(myTree root){
        List<Integer> list = new ArrayList<>();

        if (root == null ){
            return list;
        }

        Queue<myTree> queue = new LinkedList<>();

        queue.add(root);

        while (!queue.isEmpty()){
            myTree cur = queue.poll();
            
            list.add(cur.val);

            if (cur.left != null){
                queue.add(cur.left);
            }

            if (cur.right != null){
                queue.add(cur.right);
            }
        }
        return list;
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值