【数据结构】---二叉树的应用

判定两棵树是否互为镜像对称的树

 /**
     * @Description: 判定两棵树是否互为镜像对称的树
     * @Param: A的左子树和B右子树互为镜像,
     * @return:
     */
    public boolean isMirror(Node p, Node q) {
        if (p == null && q == null) {
            return true;
        } else if (p == null || q == null) {
            return false;
        }
        return p.val == q.val
                && isMirror(p.left, q.right)
                && isMirror(p.right, q.left);
    }

判断一棵树自己是否是镜像对称的

  /**
    * @Description: 判断一棵树自己是否是镜像对称的
    * @Param:
    * @return:
    */
public  boolean isSelfMiiro(Node root){
    if(root==null){
        return true;
    }
    return isMirror(root.left,root.right);
}

平衡二叉树:左子树与右子树深度相差<1 左右子数高度差不超过1

 /**
     * @Description: 平衡二叉树:左子树与右子树深度相差<1 左右子数高度差不超过1
     * soulution:遍历左子树的
     * @return:
     */
    public boolean isBalanced(Node root) {
        if(root==null){
            return true;
        }
        if(!(isBalanced(root.left))){
            return false;
        }
        if(!(isBalanced(root.right))){
            return false;
        }
        //每层都逐一计算左子树和右子树的高度
        //然后计算高度差
        //一旦有一层不符合就返回false
        int left=hight(root.left);
        int right=hight(root.right);
        int diff=left-right;
        if(diff>1||diff<-1){
            return false;
        }
        return true;
    }

private int hight(Node root) {

    if(root!=null){
        int left=hight(root.left)+1;
        int right=hight(root.right)+1;
        return left>right ? left:right;
    }
    return 0;
}

判断一棵树是否是另一个树的子树

  /**
        * @Description: 另一个树的子树
        * @Param:
        * @return:
        */
        public boolean isSubtree(Node s, Node t) {
           return findTree(s,t);
        }
   private boolean findTree(Node root,Node t){
            if(root==null && t==null){
                return true;
            }
            if(root==null ){
                return false;
            }
            if(isEqual(root,t)){
                return true;
            }
            if(findTree(root.right,t)){
                return true;
            }
            return findTree(root.left,t);
   }

创建二叉树

 /** 
    * @Description: 创建二叉树
     * 不能用普通的前序遍历创建二叉树
     * 用带空节点的前序遍历创建二叉树
     * class RV{
     *     Node root;
     *     int used;
     * }
     * public RV createTree(整棵树的前序){
     * if(整个树的长度为0){
     *     return RV={NULL.0};
     * }
     *  1.   根的值=前序[0];
     *     if(rootValue==#){
     *         创建的树是空树,当前创建子树的根节点为null,用了一个节点
     *     }
     *
     *     左子树(root.left),左子树使用的个数=createTree(整棵树的前序除去char[0])
     *     右子树(root.right),右子树使用的个数=cratTree(整棵树的前序除去第一个和左子树用掉的)
     *     return{root,根使用的个数+左子树使用的个数+右子树使用的个数}
     * }
    */

    class ReturnRoot{
      private   Node nowRoot;
       private int used;

        public ReturnRoot(Node nowRoot, int used) {
            this.nowRoot = nowRoot;
            this.used = used;
        }
    }
    public  ReturnRoot creatTree(char[] preOrder){
             if(preOrder.length==0){
                 //如果前序数组长度为0,说明没有树可以创建
                 return new ReturnRoot(null,0);
             }
             //如果长度不为0,则取出第一个节点为根节点
             if(preOrder[0]=='#'){
                 //若根节点为空,则返回根节点为空,使用了1个空节点
              return new ReturnRoot(null,1);
             }else{
             Node root= new Node(preOrder[0]);
                //第一个数组元素作为根节点,利用剩余数组继续创建树的左子树
                 char [] restLeft=Arrays.copyOfRange(preOrder,1,preOrder.length);
                //递归调用创建树,返回值为ReturnRoot
                 ReturnRoot leftReturn=creatTree(restLeft);

                 //左子树创建完后创建右子树,右子树的长度为整棵树的前序除去第一个和左子树用掉的
                 char[] restRight=Arrays.copyOfRange
                         (preOrder,preOrder.length-leftReturn.used,preOrder.length);
                 //递归调用创建右子树,返回值为ReturnRoot
                 ReturnRoot rightRoot=creatTree(restRight);
                 //把根,左子树,右子树链接在一起
                 root.left=leftReturn.nowRoot;
                 root.right=rightRoot.nowRoot;
                 //返回值为根节点,用了的长度为根+左子树用了的+右子树用了的
                 return new ReturnRoot(root,1+leftReturn.used+rightRoot.used);
             }
    }

利用前序和中序构建二叉树

/**
     * @Description: 利用前序+中序构建二叉树
     * 1在前序中找到根的值 preOrder[0]
     * 2在中序中找到根的值所在的下标--》可得到左子树的节点个数
     * 3.切出左子树的前序+中序 :preOder跳过1,长度是下标;  inOrder,长度是下标
     * 4.切出右子树的前序+中序:preOder跳过1,跳过下标(到达右子树),长度为总长-左子树长度
     * inOrder:跳过下标,跳过1,长度为总长-下标
     */
    public TreeNode buildTree12(int[] preorder, int[] inorder) {
        if (preorder == null) {
            return null;
        }
        //1.在前序中找到根的值
        TreeNode root = new TreeNode(preorder[0]);
        //2.在中序中找到根所在的下标==左子树的节点个数
        int leftSize = -1;
        for (int i = 0; i < inorder.length; i++) {
            if (inorder[i] == preorder[0]) {
                leftSize = i;
            }
        }
        //前序:ABCDE
        //中序:CDBAE
        //3.切出左子树的前序:copyOfRange()函数参数的区间--左闭右开
        int[] leftPreOrder = Arrays.copyOfRange(preorder, 1, leftSize + 1);
        //切出左子树的中序
        int[] leftInOrder = Arrays.copyOfRange(inorder, 0, leftSize);
        TreeNode rootLeft = buildTree12(leftPreOrder, leftInOrder);
        //4.切出右子树的前序
        int[] rightPreOrder = Arrays.copyOfRange(preorder, leftSize + 1, preorder.length);
        //切出右子树的中序
        int[] rightInOrder = Arrays.copyOfRange(inorder, leftSize + 1, inorder.length);
        TreeNode rightRoot = buildTree12(rightPreOrder, rightInOrder);
        root.left = rootLeft;
        root.right = rightRoot;
        return root;

    }

利用中序和后续构建二叉树

/**
     * @Description: 通过中序和后序遍历构建二叉树
     * @Param:
     * @return:
     */

    public TreeNode buildTree23(int[] inorder, int[] postorder) {
        if (inorder.length == 0) {
            return null;
        }
        //1.在后序中找到根节点
        TreeNode root = new TreeNode(postorder[postorder.length - 1]);
        //2.得到左子树的长度
        int leftSize = -1;
        for (int i = 0; i < inorder.length; i++) {
            if (inorder[i] == root.val) {
                leftSize = i;
            }
        }
        //3.切出左子树的中序
        int[] leftInOrder = Arrays.copyOfRange(inorder, 0, leftSize + 1);
        //切出左子树的后序
        int[] leftPostOrder = Arrays.copyOfRange(postorder, 0, leftSize);
        root.left = buildTree23(leftInOrder, leftPostOrder);
//    中序遍历 inorder = [9,3,15,20,7]
//    后序遍历 postorder = [9,15,7,20,3]
        //4.切出右子树的中序
        int[] rightInOrder = Arrays.copyOfRange(inorder, leftSize + 1, inorder.length);
        //切出右子树的后序:copyOfRange()函数是对索引取左闭右开
        int[] rightPostOrder = Arrays.copyOfRange(postorder, leftSize, postorder.length - 1);
        root.right = buildTree23(rightInOrder, rightPostOrder);
        return root;

    }

判断一棵树是不是完全二叉树

/**
     * @Description: 判断一棵树是不是完全二叉树
     * solution:带着空节点层序遍历,如果遇到空节点之后的所有都是空节点--》完全二叉树
     * 如果遇到空之后,又遇到飞空,不是完全二叉树
     */

    public boolean isComplete(TreeNode root) {
        if (root == null) {
            return true;
        }
        LinkedList<TreeNode> queue = new LinkedList<>();
        queue.addLast(root);
        while (true) {
            TreeNode front = queue.pollFirst();
            if (front == null) {
                //如果遇到空,就不走了,判断队列中残留的的是否全是空
                break;
            }
            queue.addFirst(front.left);
            queue.addFirst(front.right);
        }

        //循环走完了,判断空节点的后面是否还有非空
        while (!queue.isEmpty()) {
            TreeNode front = queue.pollFirst();
            if (front != null) {
                return false;
            }
        }
        return true;
    }

将一棵搜索树转换成双向链表

/**
     * @Description: 输入一棵二叉搜索树(任意一个节点的左边比右边小),
     * 将该二叉搜索树转换成一个排序的双向链表。
     * 要求不能创建任何新的结点,只能调整树中结点指针的指向
     * solution:中序是有序的
     * 将节点串成双向链表:
     * Node pre=null
     * for(Node node:list){
     * node.pre=pre;//node.left=pre;
     * if(pre!=null){
     * pre.next=node;//pre.right=node
     * }
     * pre=node;
     * }
     */
    private static TreeNode prev = null;
    private static TreeNode head = null;

    public TreeNode Convert(TreeNode pRootOfTree) {
        prev = null;
        head = null;
        inOrderSereachTree(pRootOfTree);
        return head;
    }

    public void inOrderSereachTree(TreeNode root) {
        //1.中序遍历二叉树
        //2.将中序遍历的节点穿成双向链表
        if (root != null) {
            inOrderSereachTree(root.left);
            //处理根
            buildLinkedList(root);
            inOrderSereachTree(root.right);
        }
    }

    private void buildLinkedList(TreeNode node) {
        //搜索树的任何一个节点的左孩子小于右孩子
        node.left = prev;
        if (prev != null) {
            prev.right = node;
        } else {
            head = node;
        }
        prev = node;
    }

将二叉树转化为字符串

 /**
     * @Description: 你需要采用前序遍历的方式,将一个二叉树转换成一个由括号和整数组成的字符串。
     * 空节点则用一对空括号 "()" 表示。
     * 省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对
     * @Param:
     * @return:
     */
    public String tree2str(TreeNode t) {
        if (t == null) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        //前序遍历得到节点,传入追加字符串,在第一次经过字符串时就记录下来
        preOrder(t, sb);
        sb.delete(0, 1);
        sb.delete(sb.length() - 1, sb.length());
        return sb.toString();
    }

    private void preOrder(TreeNode root, StringBuilder sb) {
        if (root != null) {
            sb.append("(");
            //第一次经过节点时就记录下来
            sb.append(root.val);
            //如果左子树为空,右子树不为空记录值()
            if (root.left == null && root.right != null) {
                sb.append("()");
            } else {
                preOrder(root.left, sb);
            }
            preOrder(root.right, sb);
            sb.append(")");
        }
    }

找到两棵子树最近的公共祖先

/**
     * @Description:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
     * “对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,
     * 满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。
     * <p>
     * 1.p或q至少有一个就是root,祖先是root
     * 2.一个在root的左子树上,一个在右子树上,公共祖先是root
     * 3.在一棵子树上,则递归到这颗子树上{
     * 递归查找子树,如果在左子树上找到了p,右子树上找到了q,就是第一种情况(递归出口)
     * * }
     * @Param:
     * @return:
     */
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        //保证节点不为空
        if (root == p || root == q) {
            return root;
        }
        boolean pInLeft = find(root.left, p);
        boolean qInLeft = find(root.left, q);
        /*
         * 三种情况:1.分布在左右两个子树上--》root
         *           2.根节点就是其中一个节点--》root
         *           3.分布在同一个子树上(递归回12)
         * */
        if (pInLeft && qInLeft) {
            //如果p在左子树上,q也在左子树上,递归查找
            return lowestCommonAncestor(root.left, p, q);
        }
        if (!pInLeft && !qInLeft) {
            //说明在右子树上
            return lowestCommonAncestor(root.right, p, q);

        }
        //说明一个在左子树上 一个在右子树上,公共祖先为根
        return root;
    }

    private boolean find(TreeNode root, TreeNode t) {
        if (root == null) {
            return false;
        }
        if (root == t) {
            return true;
        }
        if (find(root.left, t)) {
            return true;
        }
        return find(root.right, t);
    }

通过层序遍历将二叉树装进容器

 /**
     * @Description: 层序遍历,将遍历的数据装入List<List<Integer>>容器
     * solution:利用队列:一头进 一头出
     * 1.启动  根入队列
     * 2,取队首
     * 2.拉下线(空节点不要)
     */
    public List<List<Integer>> levelOrder(TreeNode root) {
        //相当于一个二维数组,给顺序链表中放顺序链表
        List<List<Integer>> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        class NodeLevel {
            TreeNode node;
            int level;

            public NodeLevel(TreeNode node, int level) {
                this.node = node;
                this.level = level;
            }
        }
        LinkedList<NodeLevel> queue = new LinkedList<>();
        //队首入队,
        queue.addLast(new NodeLevel(root, 0));
        while (!queue.isEmpty()) {
            //取队首
            NodeLevel front = queue.pollFirst();
            TreeNode node = front.node;

            int level = front.level;
            //list.size()随着遍历的层数的增加而增加
            //如果是新层,则给元顺序的增加值,这个值是一个顺序链表
            if (list.size() == level) {
                //扩展为二维数组
                list.add(new ArrayList<>());
            }
            //在当前层中对应的顺序链表中的顺序链表放值
            list.get(level).add(node.val);
            //拉下线,层数+1
            if (node.left != null) {
                queue.addLast(new NodeLevel(node.left, level + 1));
            }
            if (node.right != null) {
                //拉下线,层数+1
                queue.addLast(new NodeLevel(node.right, level + 1));
            }
        }
        return list;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值