【数据结构】 - 二叉树

目录

一  树的基本了解

 二 叉树

1.二叉树简介

2、二叉树的操作

三 二叉树的练习


一 树的基本了解

1.树的定义:

树是一种非线性的结构,由一个根节点和M个子树组成。在树型结构中,子树之间不能有交集。

2.树的概念:

  • 节点的度:一个节点含有的子树的个数。如A的度为3
  • 树的度:所有节点度的最大值。如上图树的度为3
  • 叶子节点:度为0的节点。如EFGHIJ
  • 父节点/双亲结点:一个节点有子节点,称这个节点为子节点的父节点。如A是B的父节点
  • 子节点/孩子节点:一个节点有父节点,称这个节点为父节点的子节点。如E是B的子节点
  • 根节点:没有父亲节点的节点。如A
  • 节点的层次:从根开始定义,根为第一层,根的子节点为第二层,以此类推。
  • 树的高度:最大的节点层次。如图中树的高度为3
  • 兄弟节点:具有相同的父亲节点。如EFG
  • 堂兄弟节点:双亲在同一层的节点。如EH
  • 节点的祖先:从根到该节点所经分支上的所有节点。如A是所有节点的祖先
  • 子孙:以某节点为根的子树任意分支上的节点。如所有节点都是A的子孙
  • 森林:m棵互不相交的树组成。

 二叉树

1.二叉树简介

  • 二叉树的概念

一棵二叉树由根节点加上左子树和右子树组成,二叉树不存在度大于2的节点,子树有左右之分,次序不能颠倒。

  • 特殊二叉树

满二叉树:一棵二叉树的每层节点都达到最大值,也就是说满二叉树的层数为k,节点个数为2^{k}-1

完全二叉树:完全二叉树是由满二叉树引出来的。对于深度为k、有n个节点的二叉树,当且仅当每一个节点都与深度为k的满二叉树中编号为0-n-1的节点对应,称为完全二叉树。(从上到下,从左到右)

  • 二叉树的性质

1.若根节点层数为1,则一棵非空二叉树的第 i 层最多有2^{i-1}个节点

2.深度为k的二叉树的最大节点数为2^{k}-1(k>=0)

3.叶子结点个数为n0,度为2的节点个数为n2,则n0=n2+1

(节点为n的树有n-1条边)

4.n个节点的完全二叉树的深度k在\log(n+1)上取整

5.具有n个节点的二叉树,按照从上到下从左到右的顺序对所有的节点从0开始编号,对于序号为i的节点:

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

②2i+1<n 左子树序号:2i+1 

③2i+2<n 右子树序号:2i+2

练习:

  • 二叉树的存储

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

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

2、二叉树的操作

❤️创建一棵简单的二叉树


public class BinaryTree {
    //节点
    static class TreeNode{
        public char val;
        public TreeNode left;
        public TreeNode right;

        public TreeNode(char val){
            this.val = val;
        }
    }

    public TreeNode createTree(){
        TreeNode A = 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');
        A.left = B;
        A.right = C;
        B.left = D;
        B.right = E;
        C.left = F;
        C.right = G;
        E.right = H;
        return A;
    }
}

❤️二叉树的遍历

1、前序遍历:根-左-右

2、中序遍历:左-根-右

3、后序遍历:左-右-根

4、层序遍历:自上而下,自左向右

练习:

❤️二叉树的基本操作

1、获取树中节点的个数

遍历思路:遍历一个节点计数一次

子问题思路:左子树节点个数+右子树节点个数+1

2、获取叶子节点个数

遍历思路:判断左右节点是否为空,为空的就是叶子节点

子问题思路:求当前root有多少个叶子节点。叶子节点=左树叶子节点+右树叶子节点

3、获取第k层节点个数

思路:root这棵树的第k层 = root.left第k-1层 + root.right第k-1层

4、获取二叉树高度

思路:求出左右子树最大高度+1

5、检测值为value的元素是否存在

6、层序遍历

 //2.二叉树的分层遍历
    public List<List<TreeNode>> levelOrder2(TreeNode root){
        List<List<TreeNode>> ret = new ArrayList<>();
        if(root == null){
            return ret;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            //求当前队列大小
            int size = queue.size();
            List<TreeNode> tmp = new ArrayList<>();
            while(size != 0){
                //出队列4次
                TreeNode cur = queue.poll();
                tmp.add(cur);
                size--;
                if(cur.left != null){
                    queue.offer(cur.left);
                }
                if(cur.right != null){
                    queue.offer(root.right);
                }
            }
            ret.add(tmp);
        }
        return ret;
    }

7、判断完全二叉树


    /*判断是否为完全二叉树*/
    public boolean isCompleteTree(TreeNode root){
        if(root == null){
            return true;
        }
        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 cur = queue.poll();
            if(cur != null){
                return false;
            }
        }
        return true;
    }

三 二叉树的练习


1.检查两棵树是是否相同

https://leetcode-cn.com/problems/same-tree/

 /*检查两棵树是否相同(结构上、节点上的值*/
    public boolean isSameTree(TreeNode p, TreeNode q){
        //一个为空另一个不为空
        if(p == null && q != null || p != null && q == null){
            return false;
        }

        //两个都为空
        if(p == null && q == null){
            return true;
        }

        //两个都不为空但值不相同
        if(p.val != q.val){
            return false;
        }

        //两个都不为空且值相同
        return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
    }

2.检测二叉树root中是否包含subRoot

https://leetcode-cn.com/problems/subtree-of-another-tree/


    /*检验二叉树root中是否包含subRoot*/
    public boolean isSubTree(TreeNode root, TreeNode subRoot){
        if(root == null) return false;
        if(isSameTree(root, subRoot)){
            return true;
        }
        if(isSameTree(root.left, subRoot)){
            return true;
        }
        if(isSameTree((root.right, subRoot)){
            return true;
        }
        return false;
    }

3.翻转二叉树

https://leetcode-cn.com/problems/invert-binary-tree/

//翻转二叉树
    public TreeNode invertTree(TreeNode root){
        if(root == null){
            return null;
        }
        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;

        invertTree(root.left);
        invertTree(root.right);

        return root;
    }

4.平衡二叉树判断

https://leetcode-cn.com/problems/balanced-binary-tree/

/*平衡二叉树的判断:每个节点的左右子树高度差不大于1*/
    public boolean isBalanced(TreeNode root){
        if(root == null){
            return false;
        }
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.left);

        return Math.abs(leftHeight-rightHeight)<=1
                && isBalanced(root.left)
                && isBalanced(root.right);
    }

5.对称二叉树

https://leetcode-cn.com/problems/symmetric-tree/

  /*判断对称二叉树*/
    public boolean isSymmetric(TreeNode root){
        if(root == null){
            return true;
        }
        return isSymmetricChild(root.left, root.right);
    }
    public boolean isSymmetricChild(TreeNode p, TreeNode q){
        //2.左右子树有一边为空,不对称
        if(p == null && q != null || p != null && q == null){
            return false;
        }
        //2.只有一个根节点,是对称的
        if(p == null && q == null){
            return true;
        }
        //3.左右子树都存在但是值不同
        if(p.val != q.val){
            return false;
        }
        //4.左右子树都存在并且值也相同
        return isSymmetricChild(p.left, q.left)
                && isSymmetricChild(p.right, q.right);
    }

6.遍历二叉树

/*遍历二叉树*/
    //1.使用队列
    public void levelOrder1(TreeNode root){
        if(root == null){
            return;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            TreeNode cur = queue.poll();
            System.out.println(cur.val+" ");
            if(cur.left != null){
                queue.offer(cur.left);
            }
            if(cur.right != null){
                queue.offer(root.right);
            }
        }
    }

7.非递归前序遍历二叉树

144. 二叉树的前序遍历 - 力扣(LeetCode)

  /*二叉树前序非递归遍历*/
    public void preOrderNor(TreeNode root){
        if(root == null) return;
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        TreeNode top = null;
        while(cur != null || !stack.isEmpty()){
            while(cur != null){
                stack.push(cur);
                System.out.println(cur.val + " ");//放进去,打印
                cur = cur.left;
            }
            top = stack.pop();
            cur = top.right;
        }
    }

8.非递归中序遍历二叉树

94. 二叉树的中序遍历 - 力扣(LeetCode)

 /*二叉树中序非递归遍历*/
    public void inOrderNor(TreeNode root){
        if(root == null) return;
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        TreeNode top  = null;
        while(cur != null || !stack.isEmpty()){
            while(cur != null){
                stack.push(cur);
                cur = cur.left;
            }
            top = stack.pop();
            System.out.println(top.val + " ");
            cur = top.right;
        }
    }

9.非递归后序遍历二叉树

145. 二叉树的后序遍历 - 力扣(LeetCode)

 /*二叉树后序非递归遍历*/
    public void postOrderNor(TreeNode root){
        if(root == null) return;
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        TreeNode top = null;
        TreeNode prev = null;
        while(cur != null || !stack.isEmpty()){
            while(cur != null){
                stack.push(cur);
                cur = cur.left;
            }
            top = stack.peek();
            if(top.right == null || top.right == prev){
                stack.pop();
                System.out.println(top.val + " ");
                prev = top;//当前节点被打印了
            }else{
                cur = top.right;
            }
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值