目录
上一篇已经了解了一些二叉树的基本内容,这篇来讲二叉树的基本操作。
// 前序遍历
void preOrder(TreeNode root);
// 中序遍历
void inOrder(TreeNode root);
// 后序遍历
void postOrder(TreeNode root);
// 获取树中节点的个数:遍历思路
public static int nodeSize;
void size(TreeNode root);
// 获取节点的个数:子问题的思路
int size2(TreeNode root);
//获取叶子节点的个数:遍历思路
public static int leafSize = 0;
void getLeafNodeCount1(TreeNode root);
// 获取叶子节点的个数:子问题
int getLeafNodeCount2(TreeNode root);
// 获取第K层节点的个数
int getKLevelNodeCount(TreeNode root, int k);
// 获取二叉树的高度,时间复杂度:O(N)
int getHeight(TreeNode root);
// 检测值为value的元素是否存在
TreeNode find(TreeNode root, char val);
//层序遍历
void levelOrder(TreeNode root);
// 判断一棵树是不是完全二叉树
boolean isCompleteTree(TreeNode root);

public class MyBinTree {
private class TreeNode {
char val;
TreeNode left;// 左孩子的引用,常常代表左孩子为根的整棵左子树
TreeNode right;// 右孩子的引用,常常代表右孩子为根的整棵右子树
public TreeNode(char val) {
this.val = val;
}
}
public TreeNode createTree() {
TreeNode root = new TreeNode('A');
TreeNode node1 = new TreeNode('B');
TreeNode node2 = new TreeNode('C');
TreeNode node3 = new TreeNode('D');
TreeNode node4 = new TreeNode('E');
TreeNode node5 = new TreeNode('F');
TreeNode node6 = new TreeNode('G');
TreeNode node7 = new TreeNode('H');
TreeNode node8 = new TreeNode('I');
root.left = node1;
root.right = node2;
node1.left = node3;
node1.right = node5;
node2.right = node6;
node3.left = node4;
node5.left = node7;
node5.right = node8;
return root;
}
}
"根左右":从树根开始,先遍历根节点,继续递归的遍历左子树,最后再递归的遍历右子树。
public void preOrder(TreeNode root) {
// 1.base case
if (root == null) {
return;
}
// 根
System.out.print(root.val + " ");
// 左
preOrder(root.left);
//右
preOrder(root.right);
}
"左根右":先递归的访问左子树,然后访问根节点,最后递归的访问右子树。
// 中序遍历
public void inOrder(TreeNode root) {
if (root == null) {
return;
}
// 先左子树的中序
inOrder(root.left);
// 根
System.out.print(root.val + " ");
// 再右子树的中序
inOrder(root.right);
}
"左右根":先递归的访问左子树,然后递归的访问右子树,最后访问根节点。
// 后序遍历
public void postOrder(TreeNode root) {
if (root == null) {
return;
}
// 先左子树的后序
postOrder(root.left);
// 再右子树的后序
postOrder(root.right);
// 根
System.out.print(root.val + " ");
}
借助队列先进先出的特点来遍历节点:
void levelOrder(TreeNode root) {
if (root == null){
System.out.println("这是颗空树!!!");
return;
}
// 借助队列来模拟层序遍历的过程
Deque<TreeNode> queue = new LinkedList<>();
queue.offer(root);
// 队列为空,表示所有元素访问完毕
while (!queue.isEmpty()){
TreeNode cur = queue.pop();
System.out.print(cur.val + " ");
// 依次将当前节点的左右子树依次入队
if (cur.left != null){
queue.offer(cur.left);
}
if (cur.right != null){
queue.offer(cur.right);
}
}
}
将问题拆分成根节点与左右子树的问题,解决根节点的问题再递归调用本方法解决左右子树的问题。
第一种:需要一个全局变量来保存节点的个数,每走到一个节点先判断它是否为空,为空返回,否则加上这个节点即nodeSize+1,然后再递归的访问它的左右子树。
第二种:每走到一个节点先判断它是否为空,为空返回,否则返回1 + 左子树的节点个数 + 右子树的节点个数。
public static int nodeSize;
/**
* 获取树中节点的个数:遍历思路
*/
void size(TreeNode root) {
if (root == null){
return;
}
nodeSize ++;
size(root.left);
size(root.right);
}
/**
* 获取节点的个数:子问题的思路
*/
int size2(TreeNode root) {
if (root == null) return 0;
return size2(root.left) + size2(root.right) + 1;
}
与上一个的思路类似,也是拆分成根节点与左右子树的问题再递归调用本方法。
第一种:需要一个全局变量来保存叶子节点的个数,每走到一个节点先判断它是否为空,为空返回,再判断它是否为叶子节点(它的左右子树是否为空),是则leafSize+1,然后再递归的访问它的左右子树。
第二种:每走到一个节点先判断它是否为空,为空返回,再判断它是否为叶子节点(它的左右子树是否为空),是,返回1,否则返回左子树的叶子节点个数 + 右子树的叶子节点个数。
/*
获取叶子节点的个数:遍历思路
*/
public static int leafSize = 0;
void getLeafNodeCount1(TreeNode root) {
if(root == null){
return;
}
if (root.left == null && root.right == null){
leafSize ++;
}
getLeafNodeCount1(root.left);
getLeafNodeCount1(root.right);
}
/*
获取叶子节点的个数:子问题
*/
int getLeafNodeCount2(TreeNode root) {
if (root == null) return 0;
if (root.left == null && root.right == null) {
return 1;
}
return getLeafNodeCount2(root.left) + getLeafNodeCount2(root.right);
}
(1)判断根节点是否为空或k是否合法,根节点为空或k不合法返回0
(2)再判断是否到了第k层(k == 1),是,返回1(第k层节点个数+1)
(3)否则(没到第k层)返回根节点的左右子树的叶子节点。
int getKLevelNodeCount(TreeNode root, int k) {
if (root == null || k <= 0){
return 0;
}
if (k == 1){
return 1;
}
return getKLevelNodeCount(root.left,k - 1) + getKLevelNodeCount(root.right,k - 1);
}
(1)判断根节点是否为空,根节点为空,直接返回0
(2)再判断根节点的左右子树是否为空(判断树是否只有一个节点),是,返回1
(3)返回 本层高度1 + 根节点的左右子树中高度较大的数(递归的交给getHeigth方法判断)
/*
获取二叉树的高度
时间复杂度:O(N)
*/
int getHeight(TreeNode root) {
if (root == null){
return 0;
}
if(root.left == null && root.right == null){
return 1;
}
return 1 + Math.max(getHeight(root.left),getHeight(root.right));
}
前序遍历的思路
第一种:
(1)判断根节点是否为空,根节点为空,直接返回null(不存在)
(2)判断根节点的值是否等于val,是,说明找到了该元素,返回根节点
(3)判断左子树中是否存在val,存在,返回该节点;不存在,再到右子树中寻找。
第二种:
与第一种思路一致,但是返回值使用布尔值,代码更简洁了。
// 检测值为value的元素是否存在1
TreeNode find(TreeNode root, char val) {
if (root == null){
return null;
}
if (root.val == val){
return root;
}
TreeNode node = find(root.left,val);
if (node != null){
return node;
}
return find(root.right,val);
}
// 检测值为value的元素是否存在2
public boolean contains(TreeNode root,char val){
if (root == null) {
return false;
}
if (root.val == val){
return true;
}
return contains(root.left,val) || contains(root.right,val);
}
按照层序遍历的方式遍历完全二叉树
step1:当前完全二叉树的每个节点都是度为2的节点,碰到第一个叶子节点或者只有左子树没有右子树的节点时转入step2;碰到第一个只有右子树没有左子树的节点直接返回false。
step2:当前完全二叉树全是叶子节点
boolean isCompleteTree(TreeNode root) {
Deque<TreeNode> queue = new LinkedList<>();
queue.offer(root);
boolean isStep1 = true;
while (!queue.isEmpty()){
TreeNode node = queue.poll();
if(isStep1){
if(node.left != null && node.right != null){
queue.offer(node.left);
queue.offer(node.right);
} else if (node.left != null) {
queue.offer(node.left);
isStep1 = false;
} else if (node.right != null){
return false;
}else {
isStep1 = false;
}
}else {
if(node.left != null || node.right != null){
return false;
}
}
}
return true;
}
import java.util.Deque;
import java.util.LinkedList;
public class BinaryTree {
static class TreeNode {
public char val;
public TreeNode left;//左孩子的引用
public TreeNode right;//右孩子的引用
public TreeNode(char val) {
this.val = val;
}
}
/**
* 创建一棵二叉树 返回这棵树的根节点
*
* @return
*/
public TreeNode createTree() {
TreeNode root = new TreeNode('A');
TreeNode node1 = new TreeNode('B');
TreeNode node2 = new TreeNode('C');
TreeNode node3 = new TreeNode('D');
TreeNode node4 = new TreeNode('E');
TreeNode node5 = new TreeNode('F');
TreeNode node6 = new TreeNode('G');
TreeNode node7 = new TreeNode('H');
TreeNode node8 = new TreeNode('I');
root.left = node1;
root.right = node2;
node1.left = node3;
node1.right = node5;
node2.right = node6;
node3.left = node4;
node5.left = node7;
node5.right = node8;
return root;
}
// 前序遍历
public void preOrder(TreeNode root) {
if(root == null){
return;
}
System.out.print(root.val + " ");
preOrder(root.left);
preOrder(root.right);
}
// 中序遍历
void inOrder(TreeNode root) {
if(root == null){
return;
}
inOrder(root.left);
System.out.print(root.val + " ");
inOrder(root.right);
}
// 后序遍历
void postOrder(TreeNode root) {
if(root == null){
return;
}
postOrder(root.left);
postOrder(root.right);
System.out.print(root.val + " ");
}
public static int nodeSize;
/**
* 获取树中节点的个数:遍历思路
*/
void size(TreeNode root) {
if (root == null){
return;
}
nodeSize ++;
size(root.left);
size(root.right);
}
/**
* 获取节点的个数:子问题的思路
*
* @param root
* @return
*/
int size2(TreeNode root) {
if (root == null) return 0;
return size2(root.left) + size2(root.right) + 1;
}
/*
获取叶子节点的个数:遍历思路
*/
public static int leafSize = 0;
void getLeafNodeCount1(TreeNode root) {
if(root == null){
return;
}
if (root.left == null && root.right == null){
leafSize ++;
}
getLeafNodeCount1(root.left);
getLeafNodeCount1(root.right);
}
/*
获取叶子节点的个数:子问题
*/
int getLeafNodeCount2(TreeNode root) {
if (root == null) return 0;
if (root.left == null && root.right == null) {
return 1;
}
return getLeafNodeCount2(root.left) + getLeafNodeCount2(root.right);
}
/*
获取第K层节点的个数
*/
int getKLevelNodeCount(TreeNode root, int k) {
if (root == null || k <= 0){
return 0;
}
if (k == 1){
return 1;
}
return getKLevelNodeCount(root.left,k - 1) + getKLevelNodeCount(root.right,k - 1);
}
/*
获取二叉树的高度
时间复杂度:O(N)
*/
int getHeight(TreeNode root) {
if (root == null){
return 0;
}
if(root.left == null && root.right == null){
return 1;
}
return 1 + Math.max(getHeight(root.left),getHeight(root.right));
}
// 检测值为value的元素是否存在1
TreeNode find(TreeNode root, char val) {
if (root == null){
return null;
}
if (root.val == val){
return root;
}
TreeNode node = find(root.left,val);
if (node != null){
return node;
}
return find(root.right,val);
}
// 检测树中值为val的元素是否存在2
public boolean contains(TreeNode root,char val){
if (root == null) {
return false;
}
if (root.val == val){
return true;
}
return contains(root.left,val) || contains(root.right,val);
}
//层序遍历
void levelOrder(TreeNode root) {
if (root == null){
System.out.println("这是颗空树!!!");
return;
}
Deque<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()){
TreeNode cur = queue.pop();
System.out.print(cur.val + " ");
if (cur.left != null){
queue.offer(cur.left);
}
if (cur.right != null){
queue.offer(cur.right);
}
}
}
// 判断一棵树是不是完全二叉树
boolean isCompleteTree(TreeNode root) {
Deque<TreeNode> queue = new LinkedList<>();
queue.offer(root);
boolean isStep1 = true;
while (!queue.isEmpty()){
TreeNode node = queue.poll();
if(isStep1){
if(node.left != null && node.right != null){
queue.offer(node.left);
queue.offer(node.right);
} else if (node.left != null) {
queue.offer(node.left);
isStep1 = false;
} else if (node.right != null){
return false;
}else {
isStep1 = false;
}
}else {
if(node.left != null || node.right != null){
return false;
}
}
}
return true;
}
public static void main(String[] args) {
BinaryTree tree = new BinaryTree();
TreeNode root = tree.createTree();
System.out.println("前序遍历");
tree.preOrder(root);
System.out.println();
System.out.println("中序遍历");
tree.inOrder(root);
System.out.println();
System.out.println("后序遍历");
tree.postOrder(root);
System.out.println();
System.out.println("层序遍历");
tree.levelOrder(root);
System.out.println();
System.out.println("统计树的节点个数");
tree.size(root);
System.out.println(nodeSize);
System.out.println("统计叶子节点个数");
tree.getLeafNodeCount1(root);
System.out.println(leafSize);
System.out.println("树的高度");
System.out.println(tree.getHeight(root));
System.out.println("检测树中值为val的元素是否存在");
// System.out.println(tree.find(root,'x').val);
if (tree.find(root,'Q') == null){
System.out.println("没有找到该元素");
}else {
System.out.println(tree.find(root,'x').val);
}
if (tree.find(root,'B') == null){
System.out.println("没有找到该元素");
}else {
System.out.println(tree.find(root,'B').val);
}
System.out.println("获取第K层节点的个数");
System.out.println(tree.getKLevelNodeCount(root,3));
System.out.println("判断一棵树是不是完全二叉树");
System.out.println(tree.isCompleteTree(root));
}
}

我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳
给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最
我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------
本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01 客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02 数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit