树&二叉树&模拟实现&算法结构

1、树的定义:

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

*有一个特殊的节点,成为根节点,根节点没有前驱节点

*除根结点外,其余节点被分成M个互不相交的集合T1、T2、...、Tm,其中,每一个集合Ti(1<i<m)又是一棵与树类似的子树,每棵子树的根节点都只有一个前驱,可以有0个或多个后继

*树是递归定义的

2、概念

*节点的度:一个节点含有子树的个数称为该节点的度;如上图,A的度为6

*树的度:一棵树中,所有节点的度的最大值称为树的度,如上图,树的度为6

*叶子节点或终端节点:度为0的节点成为叶子节点;如上图:B、C、H、I、....都是叶子节点
*双亲节点或父节点:若一个节点含有子节点,则这个节点称为该子节点的父节点,如上图A是B的父节点

*孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;如上图B 是A的字节点

*根节点:一棵书中没有双亲节点的节点,如上图的A

*节点的层次:从根开始定义起,根为第一层,根的字节点为第二层,依次类推

*树的高度或深度:树中节点的最大层次;如上图,树的高度为4

*非终端节点或分支节点:度不为0的节点,如上图D、E、F、G...都是分支节点
*兄弟节点:具有相同父节点的节点互为兄弟节点;如上图的B、C互为兄弟节点

*堂兄弟节点:双亲都在同一层的节点互为堂兄弟;如上图的H、I;

*节点的祖先:从根到该节点所经过的所有节点都是该节点的祖先节点,如上图A是所有节点的祖先

*子孙:以某节点为根的子树中任意节点都是该节点的子孙;如上图所有节点都是A的子孙

森林:由m棵不相交的树组成的集合称为森林

3、树的模拟实现

*定义一个树的类:孩子兄弟表示法

class Node {
  int value; // 树中存储的数据
  Node firstChild; // 第一个孩子引用
  Node nextBrother; // 下一个兄弟引用
}

4、二叉树
一棵二叉树是节点的有限集合,该集合:

1、或者为空

2、或者是由一个根节点加上两棵分别称为左右子树的二叉树组成

 由上图可以看出:

*不存在度大于2的节点

*二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

5、概念

*满二叉树:一棵二叉树,如果每层的节点树都达到最大值,则这颗树就是满二叉树,也就是说,如果一个树的层数为K,且节点总数为2^K-1,则它就是满二叉树

*完全二叉树:对于深度为k的,有n个节点的二叉树,当且仅当其每一个节点都深度为k的满二叉树中编号从0~n-1的节点——对应时称之为完全二叉树,满二叉树是一个特殊的完全二叉树

 6、二叉树的性质

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

*若规定只有根节点的二叉树的深度为1,则深度为k的二叉树的最大节点数是2^k-1(k>=0)

*对任何一棵二叉树,如果其叶子节点个数为n0,度为2的非叶子节点个数为n2,则n0=n2+1

*具有n个节点的完全二叉树的深度K为log2(k+1)上取整

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

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

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

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

7、二叉树的存储

二叉树的存储结构分为:顺序存储和类似于链表的链式存储

8、二叉树的模拟实现-孩子表示法

  //定义一个表示节点的一个类
    public static class TreeNode{
        //当前节点的值
        int value;
        //左节点
        TreeNode left;
        //右节点
        TreeNode right;

        public TreeNode(int value) {
            this.value = value;
        }
    }
    public void creat(){
        TreeNode node1=new TreeNode(1);
        TreeNode node2=new TreeNode(2);
        TreeNode node3=new TreeNode(3);
        TreeNode node4=new TreeNode(4);
        TreeNode node5=new TreeNode(5);
        TreeNode node6=new TreeNode(6);
        TreeNode node7=new TreeNode(7);
        node1.left=node2;
        node1.right=node3;
        node2.left=node4;
        node2.right=node5;
        node3.left=node6;
        node3.right=node7;
        root=node1;
    }
    public TreeNode root;

9、二叉树的遍历

*NLR:前序遍历(先序遍历)——访问根结点--->根的左子树--->根的右子树。
*LNR:中序遍历——根的左子树--->根节点--->根的右子树。
*LRN:后序遍历——根的左子树--->根的右子树--->根节点。

*先序遍历

方法1

    /**
     * 先序遍历
     * @param root
     */
    public void preOrder(TreeNode root){
        //如果节点为空就返回
        if(root==null){
            return;
        }
        //先序遍历:中左右
        //处理根节点
        System.out.println(root.value);
        //处理左子树
        preOrder(root.left);
        //处理右子树
        preOrder(root.right);
    }

方法二


    //定义一个list保存二叉树节点的值
    List<Integer> preOrderlist=new ArrayList<>();
    public List<Integer> preOederTree(TreeNode root){
        //前序遍历
        if(root==null){
            return null;
        }
        preOrderlist.add(root.value);
        preOederTree(root.right);
        preOederTree(root.left);
        return preOrderlist;
    }

方法三-子问题思路

 public List<Integer> preOrderTree1(TreeNode root){
        //定义一个list集合
        List<Integer> list=new ArrayList<>();
        //前序遍历子问题思路
        if(root==null){
            return list;
        }
        //先把根节点的值加入list集合里面
        list.add(root.value);
        //处理左子树
        List<Integer> leftNode=preOrderTree1(root.left);
        list.addAll(leftNode);
        //处理右子树
        List<Integer> rightNode=preOrderTree1(root.right);
        list.addAll(rightNode);
        return list;
    }

*中序遍历

/**
     *  中序遍历
     */
    public void minOrder(TreeNode root){
        //如果根节点为空返回
        if(root==null){
            return;
        }
        //处理左子树
        minOrder(root.left);
        //处理根节点
        System.out.println(root.value);
        //处理右子树
        minOrder(root.right);
    }

*后序遍历

//后序遍历:左-右-根
    public void bihindOrder(TreeNode root){
        //如果根节点为空返回
        if(root==null){
            return;
        }
        //处理左节点
        bihindOrder(root.left);
        //处理右节点
        bihindOrder(root.right);
        //打印根结点
        System.out.println(root.value);
    }

*节点个数

    /**
     * 节点个数
     * @param root
     * @return
     */
    public int size(TreeNode root){
        //1、终止条件,(一个空树,一个叶子节点)
        if(root==null){
            return 0;
        }
        //2、如果只有一个根节点返回1
        //3、处理左子树
        int leftTreeNode=size(root.left);
        //4、处理右子树
        int rightTreeNode=size(root.right);
        //返回节点的和:根节点+左节点+右节点
        return 1+leftTreeNode+rightTreeNode;
    }

*求叶子节点个数

1、子问题思路

子问题思路就是将一个大问题,分成N个,对于二叉树来说就是分成两个,分别去求解这些子问题,最终汇总成大问题的解

 //子问题思路,求叶子节点个数
    public int leafNode(TreeNode root){
        if(root==null){
            return 0;
        }
        if(root.left==null&&root.right==null){
            //条件满足时返回1
            return 1;
        }
        //处理左子树
        int left=leafNode(root.left);
        //处理右子树
        int right=leafNode(root.right);
        //返回左右相加的叶子节点的总和
        return left+right;
    }

2、遍历思路

 public int count;
 public int leafNode1(TreeNode root){
        if(root==null){
            return 0;
        }
        if(root.left==null&&root.right==null){
            count++;
        }
        leafNode1(root.left);
        leafNode1(root.right);
        return count;
    }

*获取第k层节点的个数

 //获取第k层节点的个数
    public int findKNode(TreeNode root,int k){
        //如果根节点或者K==0的条件下返回0
        if(root==null|| k ==0){
            return 0;
        }
        //查询终止条件
        if(k==1){
            return 1;
        }
        int leftTree=findKNode(root.left,k-1);
        int rightTree=findKNode(root.right,k-1);
        return leftTree+rightTree;
    }

*获取二叉树的高度

 //获取二叉树的高度
    public int heightTree(TreeNode root){
        //如果root为0,返回0
        if(root==null){
            return 0;
        }
        //利用Math.max()方法进行左右子树高度的判断
        int left=heightTree(root.left);
        int right=heightTree(root.right);
        int high=Math.max(left,right)+1;
        return high;
    }

*判断是否是一棵完全二叉树

//判断是否是完全二叉树
    public boolean isCompleteTree(TreeNode root){
        //定义队列结构辅助保存节点
        Queue<TreeNode> queue=new LinkedList<>();
        //首先判空条件
        if(root==null){
            return true;
        }
        //先将根节点入队
        queue.offer(root);
        //循环条件:队列不为空
        while(!queue.isEmpty()){
            //根节点出队,保存node
            TreeNode node=queue.poll();
            if(node!=null) {
                //节点不为空,不管左右节点是否为空,全部入队
                queue.offer(root.left);
                queue.offer(root.right);
            }else{
                //当node为空的时候,将队列元素全部出队,
                while(queue.isEmpty()){
                    //当出队元素不为null时就不是一个完全二叉树,返回false
                    TreeNode checkNode=queue.poll();
                    if(checkNode!=null){
                        return false;
                    }
                }
            }
        }
        //最后返回true
        return true;
    }

*层次遍历

 /**
     * 层次遍历
     * @param root
     * @return
     */
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> list1=new ArrayList<>();
        if(root==null){
            return list1;
        }
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            List<Integer> list=new ArrayList<>();
            int size=queue.size();
            while(size>0){
                TreeNode node=queue.poll();
                list.add(node.value);
                if(root.left!=null){
                    queue.offer(node.left);
                }
                if(root.right!=null){
                    queue.offer(node.right);
                }
                size--;
            }
            list1.add(list);
        }
        return list1;
    }

*测试类


public class TextBinaryTree {
    public static void main(String[] args) {
        Day20221022.Tree.BinaryTree binarytree=new BinaryTree();
        binarytree.creat();
        System.out.println(binarytree.preOederTree(binarytree.root));
        System.out.println("二叉树的节点的个数");
        System.out.println(binarytree.size(binarytree.root));
        System.out.println("子问题遍历二叉树叶子节点的个数");
        System.out.println(binarytree.leafNode(binarytree.root));
        System.out.println("遍历二叉树叶子节点个数");
        System.out.println(binarytree.leafNode1(binarytree.root));
        System.out.println("查询第K层节点的个数");
        System.out.println(binarytree.findKNode(binarytree.root,2));
        System.out.println("查询树的高度");
        System.out.println(binarytree.heightTree(binarytree.root));
        System.out.println("是否是一棵完全二叉树");
        System.out.println(binarytree.isCompleteTree(binarytree.root));
        System.out.println("===============");
    }
}

结果

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值