算法体系-12 第 十二 二叉树的基本算法 下

一 实现二叉树的按层遍历

1.1 描述

1)其实就是宽度优先遍历,用队列

2)可以通过设置flag变量的方式,来发现某一层的结束(看题目)看下边的第四题解答

1.2 代码

public class Code01_LevelTraversalBT {

    public static class Node {
        public int value;
        public Node left;
        public Node right;

        public Node(int v) {
            value = v;
        }
    }

    public static void level(Node head) {
        if (head == null) {
            return;
        }
        Queue<Node> queue = new LinkedList<>();
        queue.add(head);
        while (!queue.isEmpty()) {
            Node cur = queue.poll();
            System.out.println(cur.value);
            if (cur.left != null) {
                queue.add(cur.left);
            }
            if (cur.right != null) {
                queue.add(cur.right);
            }
        }
    }

二 实现二叉树的序列化和反序列化

2.1描述

1)先序方式序列化和反序列化

2)按层方式序列化和反序列化

将二叉树序力化为唯一的字符串叫序力化,字符串也能转出唯一的数二叉树叫反序力化

2.2 分析

2.3 前序列化代码

public static class Node {
        public int value;
        public Node left;
        public Node right;

        public Node(int data) {
            this.value = data;
        }
    }

    public static Queue<String> preSerial(Node head) {
        Queue<String> ans = new LinkedList<>();
        pres(head, ans);
        return ans;
    }

    public static void pres(Node head, Queue<String> ans) {
        if (head == null) {
            ans.add(null);
        } else {
            ans.add(String.valueOf(head.value));
            pres(head.left, ans);
            pres(head.right, ans);
        }
    }

2.4 前序反序列化

public static Node buildByPreQueue(Queue<String> prelist) {
        if (prelist == null || prelist.size() == 0) {
            return null;
        }
        return preb(prelist);
    }

    public static Node preb(Queue<String> prelist) {
        String value = prelist.poll();
        if (value == null) {
            return null;
        }
        Node head = new Node(Integer.valueOf(value));
        head.left = preb(prelist);
        head.right = preb(prelist);
        return head;
    }

2.5 中序列化代码

由上图可以知道,中序序例化是有歧义的,所以不存在中序的序列化

public static Queue<String> inSerial(Node head) {
        Queue<String> ans = new LinkedList<>();
        ins(head, ans);
        return ans;
    }

    public static void ins(Node head, Queue<String> ans) {
        if (head == null) {
            ans.add(null);
        } else {
            ins(head.left, ans);
            ans.add(String.valueOf(head.value));
            ins(head.right, ans);
        }
    }

2.7 中序反列化 

2.8 后序列化代码

public static Queue<String> posSerial(Node head) {
        Queue<String> ans = new LinkedList<>();
        poss(head, ans);
        return ans;
    }

    public static void poss(Node head, Queue<String> ans) {
        if (head == null) {
            ans.add(null);
        } else {
            poss(head.left, ans);
            poss(head.right, ans);
            ans.add(String.valueOf(head.value));
        }
    }

2.9后序反列化代码

public static Node buildByPosQueue(Queue<String> poslist) {
        if (poslist == null || poslist.size() == 0) {
            return null;
        }
        // 左右中  ->  stack(中右左) 默认是左右中,这种情况没法首先没法建立头节点,因此进行转化为头在前面的情况,把它放入stack(中右左),这是头就先出来,就可以新建head
        Stack<String> stack = new Stack<>();
        while (!poslist.isEmpty()) {
            stack.push(poslist.poll());
        }
        return posb(stack);
    }

    public static Node posb(Stack<String> posstack) {
        String value = posstack.pop();
        if (value == null) {
            return null;
        }
        Node head = new Node(Integer.valueOf(value));
        head.right = posb(posstack);
        head.left = posb(posstack);
        return head;
    }

3.0 按层序列化和反序列化

3.0.1分析

3.0.2 按层序列化 代码

public static Queue<String> levelSerial(Node head) {
        Queue<String> ans = new LinkedList<>();
        if (head == null) {
            ans.add(null);
        } else {
            ans.add(String.valueOf(head.value));
            Queue<Node> queue = new LinkedList<Node>();
            queue.add(head);
            while (!queue.isEmpty()) {
                head = queue.poll(); // head 父   子
                if (head.left != null) {
                    ans.add(String.valueOf(head.left.value));
                    queue.add(head.left);
                } else {
                    ans.add(null);
                }
                if (head.right != null) {
                    ans.add(String.valueOf(head.right.value));
                    queue.add(head.right);
                } else {
                    ans.add(null);
                }
            }
        }
        return ans;
    }

3.0.3 按层反序列化 代码


    public static Node buildByLevelQueue(Queue<String> levelList) {
        if (levelList == null || levelList.size() == 0) {
            return null;
        }
        Node head = generateNode(levelList.poll());
        Queue<Node> queue = new LinkedList<Node>();
        if (head != null) {
            queue.add(head);
        }
  //因为要记录上一次的节点,这里借用队列来完成
        Node node = null;
        while (!queue.isEmpty()) {
            node = queue.poll();
            node.left = generateNode(levelList.poll());
            node.right = generateNode(levelList.poll());
            if (node.left != null) {
                queue.add(node.left);
            }
            if (node.right != null) {
                queue.add(node.right);
            }
        }
        return head;
    }

    public static Node generateNode(String val) {
        if (val == null) {
            return null;
        }
        return new Node(Integer.valueOf(val));
    }

三 Encode N-ary Tree to Binary Tree

3.1 描述

一颗多叉树,序历化为为二叉树,二叉树也能转为原来的多叉树;

3.2 分析

第一步 先将多叉树的每个节点的孩子放在对应节点左树的右边界上;

左树的节点为该节点的第一个树,反回来看某个节点是否有孩子看该节点左数是否有右边孩子

结构如下

3.3 代码

package class11;

import java.util.ArrayList;
import java.util.List;

// 本题测试链接:https://leetcode.com/problems/encode-n-ary-tree-to-binary-tree
public class Code03_EncodeNaryTreeToBinaryTree {

    // 提交时不要提交这个类
    public static class Node {
        public int val;
        public List<Node> children;

        public Node() {
        }

        public Node(int _val) {
            val = _val;
        }

        public Node(int _val, List<Node> _children) {
            val = _val;
            children = _children;
        }
    };

    // 提交时不要提交这个类
    public static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        TreeNode(int x) {
            val = x;
        }
    }

    // 只提交这个类即可
    class Codec {
        // Encodes an n-ary tree to a binary tree.
        public TreeNode encode(Node root) {
            if (root == null) {
                return null;
            }
            TreeNode head = new TreeNode(root.val);
            head.left = en(root.children);
            return head;
        }

        private TreeNode en(List<Node> children) {
            TreeNode head = null;
            TreeNode cur = null;
            for (Node child : children) {
                TreeNode tNode = new TreeNode(child.val);
                if (head == null) {
                    head = tNode;
                } else {
                    cur.right = tNode;
                }
                cur = tNode;
                cur.left = en(child.children);
            }
            return head;
        }

        // Decodes your binary tree to an n-ary tree.
        public Node decode(TreeNode root) {
            if (root == null) {
                return null;
            }
            return new Node(root.val, de(root.left));
        }

        public List<Node> de(TreeNode root) {
            List<Node> children = new ArrayList<>();
            while (root != null) {
                Node cur = new Node(root.val, de(root.left));
                children.add(cur);
                root = root.right;
            }
            return children;
        }

    }

}

四 求二叉树最宽的层有多少个节点

4.1 描述

打印二叉树每层的的节点树及最多的节点数;

4.2 分析

根据宽度优先遍历的基础上,要是能知道哪一层结束,那么就能算出每一层的节点数;

设计两个数,Node curEnd = head; // 当前层,最右节点是谁Node nextEnd = null; // 下一层,最右节点是谁

每次遍历当前节点时候,判断该节点是否和记录的curEnd节点相等,相等就是当前层结束了,把当前层的节点数更新到max中,

再将当前节点的每一个左右孩子更新到队列中的过程中,每一步都更新nextEnd的值为当前加队列的值,下一层遍历来的时候更新curEnd值为nextEnd

4.3 代码

public static int maxWidthNoMap(Node head) {
        if (head == null) {
            return 0;
        }
        Queue<Node> queue = new LinkedList<>();
        queue.add(head);
        Node curEnd = head; // 当前层,最右节点是谁
        Node nextEnd = null; // 下一层的最右节点是谁。提前为下一层出来的end节点做准备
        int max = 0;
        int curLevelNodes = 0; // 当前层的节点数
        while (!queue.isEmpty()) {
            Node cur = queue.poll();
            if (cur.left != null) {
                queue.add(cur.left);
                nextEnd = cur.left;
            }
            if (cur.right != null) {
                queue.add(cur.right);
                nextEnd = cur.right;
            }
            curLevelNodes++;
            if (cur == curEnd) {
                max = Math.max(max, curLevelNodes);
                curLevelNodes = 0;
                curEnd = nextEnd;
            }
        }
        return max;
    }
 
 
 
 //使用额外HashMapd
 public static class Node {
        public int value;
        public Node left;
        public Node right;

        public Node(int data) {
            this.value = data;
        }
    }

    public static int maxWidthUseMap(Node head) {
        if (head == null) {
            return 0;
        }
        Queue<Node> queue = new LinkedList<>();
        queue.add(head);
        // key 在 哪一层,value
        HashMap<Node, Integer> levelMap = new HashMap<>();
        levelMap.put(head, 1);
        int curLevel = 1; // 当前你正在统计哪一层的宽度
        int curLevelNodes = 0; // 当前层curLevel层,宽度目前是多少
        int max = 0;
        while (!queue.isEmpty()) {
            Node cur = queue.poll();
            int curNodeLevel = levelMap.get(cur);
            if (cur.left != null) {
                levelMap.put(cur.left, curNodeLevel + 1);
                queue.add(cur.left);
            }
            if (cur.right != null) {
                levelMap.put(cur.right, curNodeLevel + 1);
                queue.add(cur.right);
            }
            if (curNodeLevel == curLevel) {
                curLevelNodes++;
            } else {
                max = Math.max(max, curLevelNodes);
                curLevel++;
                curLevelNodes = 1;
            }
        }
        max = Math.max(max, curLevelNodes);
        return max;
    }

五 二叉树中的某个节点,返回该节点的后继节点

5.1 描述

后继节点 :比如中序遍历,求该节点的4的后继节点,就是中序遍历遍历到该节点后的所有节点

二叉树结构如下定义:

Class Node {

V value;

Node left;

Node right;

Node parent;

}

给你二叉树中的某个节点,返回该节点的后继节点

5.2 分析 中序遍历

5.2.1 方案一 先通过parrent 找到的他的跟节点后,然后通root找到他的中序遍历,然后就可以找到该节点的后继节点

方案二

5.2.2 情况1一 如果该节点有右数,那么他的后继节点一定是他右树的最左侧节点

情况二 当该节点没有右树的时候,去找该节点是谁的节点左树的最右侧节点(中序遍历的本质理解)如果没有右子树,根据中序遍历的特点,下一个就应该是去找该节点是谁的节点左树的最右侧节点

情况二 讨论如下 找一个数的后继节点,一直往上找,通过找到该节点的最后一个父节点,该节点的右子树就是他的后继节点

如下,x是y左数的最右节点,所以打印完x就该打印y了 == 找的就是那个左树上的最右节点

5.3 代码

public class Code06_SuccessorNode {

    public static class Node {
        public int value;
        public Node left;
        public Node right;
        public Node parent;

        public Node(int data) {
            this.value = data;
        }
    }

    public static Node getSuccessorNode(Node node) {
        if (node == null) {
            return node;
        }
        if (node.right != null) {
            return getLeftMost(node.right);
        } else { // 无右子树
            Node parent = node.parent;
            while (parent != null && parent.right == node) { // 当前节点是其父亲节点右孩子
                node = parent;
                parent = node.parent;
            }
            return parent;
        }
    }

    public static Node getLeftMost(Node node) {
        if (node == null) {
            return node;
        }
        while (node.left != null) {
            node = node.left;
        }
        return node;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/481928.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ChatGPT无法登录,提示我们检测到可疑的登录行为?如何解决?

OnlyFans 订阅教程移步&#xff1a;【保姆级】2024年最新Onlyfans订阅教程 Midjourney 订阅教程移步&#xff1a; 【一看就会】五分钟完成MidJourney订阅 GPT-4.0 升级教程移步&#xff1a;五分钟开通GPT4.0 如果你需要使用Wildcard开通GPT4、Midjourney或是Onlyfans的话&am…

分享:vue3+OpenTiny UI+cesium 实现三维地球

效果图 使用vue3 OpenTiny UI cesium 实现三维地球 node.js > v16.0 opentiny vue3 ui安装指南 https://opentiny.design/tiny-vue/zh-CN/os-theme/docs/installation yarn add opentiny/vue3 项目依赖 "dependencies": {"opentiny/vue": "3…

洛谷_P1873 [COCI 2011/2012 #5] EKO / 砍树_python写法

P1873 [COCI 2011/2012 #5] EKO / 砍树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) n, m map(int,input().split())data list(map(int,input().split())) h 0 def check(mid):h 0for i in data:if i>mid:h (i-mid)if h < m:return Trueelse:return Falsel 0 r …

工作需求,Vue实现登录

加油&#xff0c;新时代打工人&#xff01; vue 2.x Element UI <template><div class"body" :style"{background-image: url(${require(/assets/images/login.png)})}"><el-form :rules"rules" ref"loginForm" :mode…

【AI】发现一款运行成本较低的SelfHosting语言模型

【背景】 作为一个想构建局域网AI服务的屌丝,一直苦恼的自然是有限的资源下有没有对Spec要求低一点的SelfHosting的AI服务框架了。今天给大家介绍这款听起来有点希望,但是我也还没试验过,感兴趣的可以去尝试看看。 【介绍】 大模型生成式AI与别的技术不同,由于资源要求高…

PHP+MySQL开发组合:智慧同城便民信息小程序源码系统 带完整的安装代码包以及安装部署教程

当前&#xff0c;城市生活的节奏日益加快&#xff0c;人们对各类便民信息的需求也愈发迫切。无论是寻找家政服务、二手交易&#xff0c;还是发布租房、求职信息&#xff0c;一个高效、便捷的信息平台显得尤为重要。传统的信息发布方式往往存在信息更新不及时、查找困难等问题&a…

数据结构难点——线索二叉树的详解

线索二叉树 线索二叉树的出现中序二叉树不使用中序线索二叉树使用中序线索二叉树&#xff08;难点&#xff09; 注&#xff1a; 在阅读这篇文章之前&#xff0c;建议读者先掌握递归的概念和原理&#xff0c;以便更好地理解和欣赏文章中的内容。 线索二叉树的出现 普通二叉树的…

NFT交易市场-后端开发

首先我们需要配置好我们的ipfs&#xff0c;参考官方文档 1.https://docs.ipfs.tech/install/command-line/#system-requirementshttps://docs.ipfs.tech/how-to/command-line-quick-start/#initialize-the-repository 首先新建一个文件夹 然后在终端输入npm init -y命令进行初…

docker 和K8S知识分享

docker知识&#xff1a; 比如写了个项目&#xff0c;并且在本地调试没有任务问题&#xff0c;这时候你想在另外一台电脑或者服务器运行&#xff0c;那么你需要在另外一台电脑或者服务器配置相同的软件&#xff0c;比如数据库&#xff0c;web服务器&#xff0c;必要的插件和库等…

QT学习第一天,创建工程文件,创建按钮,对象树的概念

创建qt 方式一&#xff1a;欢迎》project》new project 方式二&#xff1a;菜单栏》文件》新建文件或项目 打开项目 方式1&#xff1a; 欢迎》project》open project 方式2&#xff1a;打开目录&#xff08;页面上不存在的项目&#xff09; 创建工程时需要注意&#xff1…

try langchain (by quqi99)

作者&#xff1a;张华 发表于&#xff1a;2024-03-18 版权声明&#xff1a;可以任意转载&#xff0c;转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明(http://blog.csdn.net/quqi99) 基于Gemma的测试环境搭建 想学习一个langchain, 所以先运行一下langchain…

8个国产全能型AI写作神器,给个标题就能自动生成全文 #其他#知识分享

国外ChatGPT爆火&#xff0c;AI写作在国内也引起不小的瞩目&#xff0c;目前国内的AI写作工具少说也有几十上百个&#xff0c;要在这么多AI写作中找出适合自己的工具&#xff0c;一个一个尝试是不太现实的&#xff0c;所以今天就给大家推荐一些款AI写作工具。帮助你少走弯路&am…

【黄啊码】使用cloudflare搭建OpenAI的接口

现在&#xff0c;我们可以使用cloudflare自己搭建一个OpenAI代理服务&#xff0c;使用我们自己的转发代理 第一步&#xff1a;注册cloudflare账号 前往官方网站注册一个账户 第二步&#xff1a;创建worker&#xff0c;进行请求中转 名字可以自己随便取一个&#xff0c;点击快…

GraalVM详细安装及打包springboot、java、javafx使用教程(打包springboot3篇)

前言 在当前多元化开发环境下&#xff0c;Java作为一种广泛应用的编程语言&#xff0c;其应用部署效率与灵活性的重要性日益凸显。Spring Boot框架以其简洁的配置和强大的功能深受开发者喜爱&#xff0c;而JavaFX则为开发者提供了构建丰富桌面客户端应用的能力。然而&#xff…

STC89C52单片机启动--综合案例秒表

代码功能&#xff1a; 1.自动开始计数&#xff0c;一共5个数码管来显示时间。一位数码管显示0-9&#xff0c;对应分度值是0.1s&#xff1b;两位数码管显示00-59&#xff0c;对应分度值1s&#xff1b;两位数码管显示00-59&#xff0c;对应分度值1min&#xff1b;上电后自动开始计…

C# 提示信息的几种方式,总有一种是你不知道的

很久没写文章了&#xff0c;今天有时间就总结一下关于提示信息的几种写法。 &#xff08;1&#xff09;第一种提示信息是winform中的提示信息MessageBox.Show() 开发C#的朋友们肯定都用过这个提示信息&#xff0c;这个方法中有几个参数。 平时用的比较多的形式有&#xff1a;…

Springboot笔记-03

1.properties配置文件 #配制oerson的值 person.lastname张三 person.age12 person.birth2017/12/12 person.bossfalse person.dog.namedag person.dog.age15 person.maps.k1v1 person.maps.k212 person.listsa,b,c运行结果乱码 因为idea默认是utf-8编码而properties是ascall编…

奇客PDF评论:优点、缺点和个人的结论

作为一个在职业中接触大量PDF文档的人&#xff0c;PDF编辑器对我来说是基本必需品。我希望我的 PDF 编辑器使用起来非常简单&#xff0c;同时还提供普通的编辑和转换功能。 我对功能足够强大、又不失简单性的 PDF 编辑器的追求最初让我想到了奇客PDF。 在过去的1年里我一直在…

Stompy:一款针对时间戳的Timestomp工具

关于Stompy Stompy是一款功能强大的时间戳管理工具&#xff0c;在该工具的帮助下&#xff0c;广大研究人员能够轻松对指定文件或目录的时间戳进行修改和操作。该工具基于PowerShell开发&#xff0c;并且支持对目标目录中的所有文件执行递归时间戳操作。 功能介绍 1、修改独立…

鸿蒙Harmony应用开发—ArkTS(@Extend装饰器:定义扩展组件样式)

在前文的示例中&#xff0c;可以使用Styles用于样式的扩展&#xff0c;在Styles的基础上&#xff0c;我们提供了Extend&#xff0c;用于扩展原生组件样式。 说明&#xff1a; 从API version 9开始&#xff0c;该装饰器支持在ArkTS卡片中使用。 装饰器使用说明 语法 Extend(UI…