阅读该文章预计60分钟
文章目录
一:二叉树的遍历
1.1:题目描述
实现二叉树的先序、中序、后序遍历,包括递归方式和非递归方式
1.2:思路分析
递归
递归遍历二叉树是相对来说比较容易的
如果当前节点为空,则返回
将节点的左右孩子递归
如果打印语句放在第一次来到递归函数,也就是左孩子递归的前面,就是前序
如果打印语句放在第二次来到递归函数,也就是左孩子递归的后面,右孩子的前面,就是中序
如果打印语句放在第三次来到递归函数,也就是右孩子递归的后面,就是前序
非递归
前序非递归遍历二叉树
前序非递归遍历二叉树
递归过程用到了系统的栈帮我们实现的
如果非递归过程就需要我们申请额外空间来记录元素
我们可以用栈来记录我们的元素
由于是前序,我们遵循打印顺序:父节点-左孩子-右孩子
故,如果我们使用栈,需将右孩子放入栈,左孩子再放入栈
依次递归
详细请看代码!
中序非递归遍历二叉树
QAQ ~~~~~~~~~~~~~~呜呜呜搞了好久才搞出来
中序非递归遍历二叉树
递归过程用到了系统栈,我们不递归,就需要一个队列或者栈来实现
这里我们使用栈
如果我们的栈不为空或者我们的处理节点不为空,
我们从栈中消费一个元素
一直遍历他的左孩子,并放到栈中,并且当前左孩子当作处理节点(这样才能一直找到左边界)
如果左孩子为空了,那么弹出当前元素,把右孩子当作当前节点,继续遍历。
你品,每个节点,先处理左节点,然后再弹出自己,然后再处理右节点。
详细看代码!
后续非递归遍历二叉树
啊 这个 反正不简单 看看吧 我debug好久才调整好边界
后序非递归二叉树
递归过程用到了系统栈,我们不递归,就需要一个队列或者栈
我们用一个栈
将头节点压栈
如果当前栈不为空,则消费一个数据
如果该数据的右孩子不为空则压入右孩子
如果该数据的左孩子不为空则压入左孩子
记录上一个被弹出的节点,
如果上一个弹出的节点是左孩子,或者右孩子,则左孩子不压栈了
如果上一个弹出的节点是右孩子,则右孩子不压栈了
如果都不满足,开始弹栈
详细请看代码
1.3:Java代码
package xyz.fudongyang.basic.class_04.my;
import java.util.Stack;
public class Code_01_PreInPosTraversal {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static void preOrderRecur(Node head) {
if (head == null) {
return;
}
System.out.print(head.value + " ");
preOrderRecur(head.left);
preOrderRecur(head.right);
}
public static void inOrderRecur(Node head) {
if (head == null) {
return;
}
preOrderRecur(head.left);
System.out.print(head.value + " ");
preOrderRecur(head.right);
}
public static void posOrderRecur(Node head) {
if (head == null) {
return;
}
preOrderRecur(head.left);
preOrderRecur(head.right);
System.out.print(head.value + " ");
}
// 非递归前序
public static void preOrderUnRecur(Node head) {
System.out.print("pre-order: ");
if (head == null) {
return;
}
Stack<Node> stack = new Stack<>();
stack.push(head);
Node pop;
while (!stack.isEmpty()) {
pop = stack.pop();
System.out.print(pop.value + " ");
if (pop.right != null) {
stack.push(pop.right);
}
if (pop.left != null) {
stack.push(pop.left);
}
}
System.out.println();
}
// 非递归中序
public static void inOrderUnRecur(Node head) {
if (head == null) {
return;
}
System.out.print("inOrderUnRecur:");
// 准备一个栈,用于保存数据以及先后顺序
Stack<Node> stack = new Stack<>();
// 把每个节点都当作头节点,榨干他的左孩子
while (!stack.isEmpty() || head != null) {
if (head != null) {
// 把当前节点压入栈,继续榨干他的左孩子
stack.push(head);
head = head.left;
} else {
// 已经没有左孩子了,那么终于可以打印自己了,打印完后让右孩子继续榨干它的左孩子
Node pop = stack.pop();
System.out.print(pop.value + " ");
head = pop.right;
}
}
System.out.println();
}
// 非递归后续
public static void posOrderUnRecur1(Node head) {
if (head == null) {
return;
}
System.out.print("posOrderUnRecur1: ");
Stack<Node> stack = new Stack<>();
stack.push(head);
Node peek;
while (!stack.isEmpty()) {
peek = stack.peek();
// 左孩子,右孩子回来的都不能再执行
if (peek.left != null && peek.left != head && peek.right != head) {
stack.push(peek.left);
} else if (peek.right != null && peek.right != head) { // 我的右孩子加过,不用再加
stack.push(peek.right);
} else {
Node pop = stack.pop();
System.out.print(pop.value + " ");
head = pop;
}
}
System.out.println();
}
public static void main(String[] args) {
/**
* 5
* 3 8
* 2 4 7 10
* 1 6 9 11
*
*/
Node head = new Node(5);
head.left = new Node(3);
head.right = new Node(8);
head.left.left = new Node(2);
head.left.right = new Node(4);
head.left.left.left = new Node(1);
head.right.left = new Node(7);
head.right.left.left = new Node(6);
head.right.right = new Node(10);
head.right.right.left = new Node(9);
head.right.right.right = new Node(11);
// recursive
System.out.println("==============recursive==============");
System.out.print("pre-order: ");
preOrderRecur(head);
System.out.println();
System.out.print("in-order: ");
inOrderRecur(head);
System.out.println();
System.out.print("pos-order: ");
posOrderRecur(head);
System.out.println();
// unrecursive
System.out.println("============unrecursive=============");
preOrderUnRecur(head);
inOrderUnRecur(head);
posOrderUnRecur1(head);
// posOrderUnRecur2(head);
}
}
二:找到二叉树的后继节点
2.1:题目描述
在二叉树中找到一个节点的后继节点
【题目】 现在有一种新的二叉树节点类型如下:
public static class Node {
public int value;
public Node left;
public Node right;
public Node parent;
public Node(int data) {
this.value = data;
}
}
该结构比普通二叉树节点结构多了一个指向父节点的parent指针。假设有一 棵Node类型的节点组成的二叉树,树中每个节点的parent指针都正确地指向 自己的父节点,头节点的parent指向null。只给一个在二叉树中的某个节点 node,请实现返回node的后继节点的函数。在二叉树的中序遍历的序列中, node的下一个节点叫作node的后继节点。
2.2:思路讲解
在二叉树中找到下一个节点 并且有parent指针
我们拿一个普通节点来判断
如果它有右孩子,那么我只需要找到它的右孩子的最左孩子就行
这样它的后续节点就是它右孩子的最左节点
如果它没有右孩子并且它是它父亲的左孩子,那么它的下一个节点就是父亲
如果它没有右孩子并且它是它父亲的右孩子,那么一直找他的父亲,知道它的父亲是祖先的左孩子位置
详细代码如下
2.3:Java代码
package xyz.fudongyang.basic.class_04.my;
public class Code_03_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 null;
}
if (node.right != null){
return getLeftMost(node.right);
}else {
Node parent = node.parent;
while (parent != null && parent.left != node){
node = parent;
parent = parent.parent;
}
return parent;
}
}
public static Node getLeftMost(Node node) {
if (node == null){
return null;
}
while (node.left != null){
node = node.left;
}
return node;
}
public static void main(String[] args) {
Node head = new Node(6);
head.parent = null;
head.left = new Node(3);
head.left.parent = head;
head.left.left = new Node(1);
head.left.left.parent = head.left;
head.left.left.right = new Node(2);
head.left.left.right.parent = head.left.left;
head.left.right = new Node(4);
head.left.right.parent = head.left;
head.left.right.right = new Node(5);
head.left.right.right.parent = head.left.right;
head.right = new Node(9);
head.right.parent = head;
head.right.left = new Node(8);
head.right.left.parent = head.right;
head.right.left.left = new Node(7);
head.right.left.left.parent = head.right.left;
head.right.right = new Node(10);
head.right.right.parent = head.right;
Node test = head.left.left;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head.left.left.right;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head.left;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head.left.right;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head.left.right.right;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head.right.left.left;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head.right.left;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head.right;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head.right.right; // 10's next is null
System.out.println(test.value + " next: " + getSuccessorNode(test));
}
}
三:二叉树的序列化和反序列化
3.1:题目介绍
先序序列、反序列化二叉树
层序序列、反序列化二叉树
3.2:思路讲解
先序序列化、反序列化
先序序列二叉树:
递归遍历二叉树,如果碰到null,就填充特殊字符,例如“#”
每个指针的结尾都需要一个结尾符号,例如“!”
返回一个字符串
先序反序列化二叉树:
拿到字符串后,按照我们的结尾符号进行分割
因为是先序遍历,所以我们先把它放入一个队列里面,方便处理
这里需要一个递归函数,功能如下
从队列取一个值,进行封装这个值,如果这个值不等于null(#),那就new一个node,并把value传进去
它需要它的左孩子
它需要它的右孩子
它的左孩子就是左孩子去递归,丰富自己
它的右孩子就是右孩子去递归,丰富自己
详细看代码
层序序列化、反序列化
层序序列化:
首先要知道如何层序遍历二叉树
很简单,把头节点放入队列中
消费队列的值,当队列不为空的时候,如果左孩子、右孩子不为空,分别放入
我们这样序列化我们二叉树,遇到null序列化为“#!”,其他值为“{value}!”
层序反序列化:
首先将字符串按照结尾符分割,得到所有节点数值
将头节点放入队列中
遍历字符串数组,从队列中拿到值,
将数组的下一个当作值的左孩子,当数组的下第二个当作值的右孩子
把左孩子,右孩子放入队列中。
直到队列为空或者数组为空
3.3:Java代码
package xyz.fudongyang.basic.class_04.my;
import java.util.LinkedList;
import java.util.Queue;
public class Code_04_SerializeAndReconstructTree {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static String serialByPre(Node head) {
// base case
if (head == null){
return "#!";
}
String res = head.value+"!";
res += serialByPre(head.left);
res += serialByPre(head.right);
return res;
}
public static Node reconByPreString(String preStr) {
String[] split = preStr.split("!");
// 因为是先序遍历,需要用队列
Queue<String> queue = new LinkedList<>();
for (String s : split) {
// 如果插入失败返回false
queue.offer(s);
}
return reconPreOrder(queue);
}
public static Node reconPreOrder(Queue<String> queue) {
String poll = queue.poll();
if ("#".equals(poll)){
return null;
}
Node node = new Node(Integer.parseInt(poll));
node.left = reconPreOrder(queue);
node.right = reconPreOrder(queue);
return node;
}
public static String serialByLevel(Node head) {
if (head == null){
return "#!";
}
StringBuilder res = new StringBuilder();
res.append(head.value).append("!");
Queue<Node> queue = new LinkedList<>();
queue.add(head);
while (!queue.isEmpty()){
Node poll = queue.poll();
if (poll.left!= null){
res.append(poll.left.value).append("!");
queue.add(poll.left);
}else {
res.append("#!");
}
if (poll.right!=null){
res.append(poll.right.value).append("!");
queue.add(poll.right);
}else {
res.append("#!");
}
}
return res.toString();
}
public static Node reconByLevelString(String levelStr) {
if(levelStr == null){
return null;
}
String[] split = levelStr.split("!");
int i = 0;
if ("#".equals(split[i])){
return null;
}
Node node = new Node(Integer.parseInt(split[i++]));
Queue<Node> queue = new LinkedList<>();
queue.add(node);
while (!queue.isEmpty()){
Node poll = queue.poll();
String split1 = split[i];
Node left = null;
if (!"#".equals(split1)){
left = new Node(Integer.parseInt(split[i]));
}
i++;
String split2 = split[i];
Node right = null;
if (!"#".equals(split2)){
right = new Node(Integer.parseInt(split[i]));
}
i++;
poll.left = left;
poll.right = right;
if (left!= null){
queue.add(left);
}
if (right != null){
queue.add(right);
}
}
return node;
}
public static Node generateNodeByString(String val) {
if (val.equals("#")) {
return null;
}
return new Node(Integer.valueOf(val));
}
// for test -- print tree
public static void printTree(Node head) {
System.out.println("Binary Tree:");
printInOrder(head, 0, "H", 17);
System.out.println();
}
public static void printInOrder(Node head, int height, String to, int len) {
if (head == null) {
return;
}
printInOrder(head.right, height + 1, "v", len);
String val = to + head.value + to;
int lenM = val.length();
int lenL = (len - lenM) / 2;
int lenR = len - lenM - lenL;
val = getSpace(lenL) + val + getSpace(lenR);
System.out.println(getSpace(height * len) + val);
printInOrder(head.left, height + 1, "^", len);
}
public static String getSpace(int num) {
String space = " ";
StringBuffer buf = new StringBuffer("");
for (int i = 0; i < num; i++) {
buf.append(space);
}
return buf.toString();
}
public static void main(String[] args) {
Node head = null;
printTree(head);
String pre = serialByPre(head);
System.out.println("serialize tree by pre-order: " + pre);
head = reconByPreString(pre);
System.out.print("reconstruct tree by pre-order, ");
printTree(head);
String level = serialByLevel(head);
System.out.println("serialize tree by level: " + level);
head = reconByLevelString(level);
System.out.print("reconstruct tree by level, ");
printTree(head);
System.out.println("====================================");
head = new Node(1);
printTree(head);
pre = serialByPre(head);
System.out.println("serialize tree by pre-order: " + pre);
head = reconByPreString(pre);
System.out.print("reconstruct tree by pre-order, ");
printTree(head);
level = serialByLevel(head);
System.out.println("serialize tree by level: " + level);
head = reconByLevelString(level);
System.out.print("reconstruct tree by level, ");
printTree(head);
System.out.println("====================================");
head = new Node(1);
head.left = new Node(2);
head.right = new Node(3);
head.left.left = new Node(4);
head.right.right = new Node(5);
printTree(head);
pre = serialByPre(head);
System.out.println("serialize tree by pre-order: " + pre);
head = reconByPreString(pre);
System.out.print("reconstruct tree by pre-order, ");
printTree(head);
level = serialByLevel(head);
System.out.println("serialize tree by level: " + level);
head = reconByLevelString(level);
System.out.print("reconstruct tree by level, ");
printTree(head);
System.out.println("====================================");
head = new Node(100);
head.left = new Node(21);
head.left.left = new Node(37);
head.right = new Node(-42);
head.right.left = new Node(0);
head.right.right = new Node(666);
printTree(head);
pre = serialByPre(head);
System.out.println("serialize tree by pre-order: " + pre);
head = reconByPreString(pre);
System.out.print("reconstruct tree by pre-order, ");
printTree(head);
level = serialByLevel(head);
System.out.println("serialize tree by level: " + level);
head = reconByLevelString(level);
System.out.print("reconstruct tree by level, ");
printTree(head);
System.out.println("====================================");
}
}
四:判断是否是平衡二叉树
4.1:思路讲解
判断一个二叉树是否是平衡二叉树
啥是平衡二叉树?
就是任意一个节点的左子树和右子树的高度差不超过1
拿一个普通的节点来说
我需要我左孩子的高度
我需要我右孩子的高度
然后如果我两个孩子的高度差超过1那就不用判断了,肯定是不平衡的
如果高度差不超过1,找到最高的那一个,加上1(本节点),就是本节点的高度。嘻嘻
看代码把~
4.2:Java代码
package xyz.fudongyang.basic.class_04.my;
public class Code_06_IsBalancedTree {
public static class TreeNode {
private int value;
private TreeNode left;
private TreeNode right;
public TreeNode(int value) {
this.value = value;
}
}
public static class Result{
private final boolean isBalanced;
private int level;
public Result(boolean isBalanced,int level){
this.isBalanced = isBalanced;
this.level = level;
}
}
private static boolean isBalancedTree(TreeNode head){
Result result = isBalancedTree(head, new Result(true,1));
return result.isBalanced;
}
private static Result isBalancedTree(TreeNode head,Result result){
/**
* 我的左边是否是平衡二叉树
* 我的右边是否是平衡二叉树
* 我左边的层高
* 我右边的层高
* 我左右的层高决定我这一层是不是平衡二叉树
*
*/
if (head == null){
result.level = result.level - 1;
return result;
}
Result resultLeft = new Result(result.isBalanced,result.level+1);
Result resultRight = new Result(result.isBalanced,result.level+1);
Result lTreeNode = isBalancedTree(head.left,resultLeft);
if (!lTreeNode.isBalanced){
return lTreeNode;
}
Result rTreeNode = isBalancedTree(head.right,resultRight);
if (!rTreeNode.isBalanced){
return rTreeNode;
}
if (Math.abs(rTreeNode.level - lTreeNode.level) > 1){
return new Result(false,Math.max(rTreeNode.level,lTreeNode.level));
}
return new Result(true,Math.max(rTreeNode.level,lTreeNode.level));
}
public static void main(String[] args) {
TreeNode treeNode = new TreeNode(1);
// TreeNode.left = new TreeNode(2);
// TreeNode.right = new TreeNode(3);
// TreeNode.left.left = new TreeNode(4);
// TreeNode.left.right = new TreeNode(5);
// TreeNode.right.left = new TreeNode(6);
// TreeNode.right.right = new TreeNode(7);
// TreeNode.left.left.left = new TreeNode(10);
// TreeNode.left.right.left = new TreeNode(10);
// TreeNode.left.right.right = new TreeNode(10);
// TreeNode.left.right.left.left = new TreeNode(10);
// TreeNode.left.right.left.right = new TreeNode(10);
treeNode.right = new TreeNode(2);
treeNode.right.right = new TreeNode(3);
System.out.println(isBalancedTree(treeNode));
}
}
五:是否是搜索二叉树
5.1:思路讲解
什么是搜索二叉树?
就是一个节点,我的左孩子如果存在,只能比我小
我的右孩子存在,只能比我大
如果不满足就不是搜索二叉树
换言之
二叉树的中序遍历必须是升序的
ok,那么我非递归中序遍历二叉树,记录上一个节点的值
我只需要比较当前节点的值,和我前一个节点的值的大小关系就ok了
如果没有前一个节点大,那么我中序遍历就不是升序的
那么我就不是搜索二叉树
直接返回false
如果一直都是升序的,那就是搜索二叉树
嘻嘻看代码吧~
5.2:Java代码
package xyz.fudongyang.basic.class_04.my;
import java.util.Stack;
public class Code_07_IsBSTAndCBT {
public static class TreeNode {
public int value;
public TreeNode left;
public TreeNode right;
public TreeNode(int data) {
this.value = data;
}
}
public static class ResultBST {
private int max;
private int min;
private boolean isBST;
public ResultBST(int max, int min, boolean isBST) {
this.min = min;
this.max = max;
this.isBST = isBST;
}
}
public static boolean isBSTree(TreeNode TreeNode) {
/**
* 左节点的最大值
* 左树是否是搜索二叉树
*
* 右节点的最小值
* 右树是否是搜索二叉树
*
* 整体记录最小值,最大值,是否是搜索二叉树
* 记录最小值、最大值同时把自己也算上
*
*/
return isBST(TreeNode);
}
public static boolean isBST(TreeNode treeNode) {
boolean result = true;
// 非递归中序遍历二叉树
if (treeNode == null) {
return true;
}
Stack<TreeNode> stack = new Stack<>();
Integer pre = null;
while (!stack.isEmpty() || treeNode != null) {
if (treeNode != null) {
stack.push(treeNode);
treeNode = treeNode.left;
} else {
TreeNode pop = stack.pop();
if (pre == null) {
pre = pop.value;
} else {
if (pop.value <= pre) {
return false;
}
}
treeNode = pop.right;
}
}
return true;
}
public static void main(String[] args) {
// TreeNode head = new TreeNode(4);
// head.left = new TreeNode(2);
// head.right = new TreeNode(6);
// head.left.left = new TreeNode(1);
// head.left.right = new TreeNode(3);
// head.right.left = new TreeNode(5);
// TreeNode head1 = new TreeNode(5);
// head1.left = new TreeNode(1);
// head1.right = new TreeNode(4);
// head1.right.left = new TreeNode(3);
// head1.right.right = new TreeNode(6);
// System.out.println(isBSTree(head1));
PreTree.Node head = new PreTree.Node(1);
head.left = new PreTree.Node(2);
head.right = new PreTree.Node(3);
head.left.left = new PreTree.Node(4);
head.left.right = new PreTree.Node(5);
head.right.left = new PreTree.Node(6);
head.right.right = new PreTree.Node(7);
head.left.left.left = new PreTree.Node(8);
TreeNode treeNode = new TreeNode(Integer.MAX_VALUE);
System.out.println(isBSTree(treeNode));
}
}
六:是否是完全二叉树
6.1:思路讲解
完全二叉树不是满二叉树
完全二叉树就是,如果二叉树的最后一层不是满的,那么除最后一层外,其他层必须是满的
而且,最后一层,之后一个元素必须是它的父亲的左孩子,不能是右孩子。
前提背景:层序遍历二叉树
换言之
如果我有右孩子没有左孩子,不是完全二叉树
如果我有左孩子没有右孩子,那么以后所有的节点都是叶节点
如果我左右孩子都有,那么加入队列,继续层序遍历
看代码吧!
6.2:Java代码
package xyz.fudongyang.basic.class_04.my;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
public class Code_07_IsBSTAndCBT {
public static class TreeNode {
public int value;
public TreeNode left;
public TreeNode right;
public TreeNode(int data) {
this.value = data;
}
}
public static class ResultBST {
private int max;
private int min;
private boolean isBST;
public ResultBST(int max, int min, boolean isBST) {
this.min = min;
this.max = max;
this.isBST = isBST;
}
}
public static boolean isCBT(TreeNode treeNode) {
if (treeNode == null) {
return true;
}
/**
* 前提:层序遍历二叉树
* 1. 我只有右孩子没有左孩子 直接失败
* 2. 我有左孩子没有右孩子 则以后层序遍历的所有节点都是叶节点(没有孩子)
*
*/
Queue<TreeNode> queue = new LinkedList<>();
queue.add(treeNode);
TreeNode leftNode;
TreeNode rightNode;
boolean isBegin = false;
while (!queue.isEmpty()) {
TreeNode poll = queue.poll();
leftNode = poll.left;
rightNode = poll.right;
if (leftNode == null && rightNode != null || isBegin && leftNode != null) {
return false;
}
if (leftNode != null) {
queue.add(leftNode);
}
if (rightNode != null) {
queue.add(rightNode);
}
if (leftNode != null && rightNode == null) {
isBegin = true;
}
}
return true;
}
public static void main(String[] args) {
// TreeNode head = new TreeNode(4);
// head.left = new TreeNode(2);
// head.right = new TreeNode(6);
// head.left.left = new TreeNode(1);
// head.left.right = new TreeNode(3);
// head.right.left = new TreeNode(5);
// TreeNode head1 = new TreeNode(5);
// head1.left = new TreeNode(1);
// head1.right = new TreeNode(4);
// head1.right.left = new TreeNode(3);
// head1.right.right = new TreeNode(6);
// System.out.println(isBSTree(head1));
PreTree.Node head = new PreTree.Node(1);
head.left = new PreTree.Node(2);
head.right = new PreTree.Node(3);
head.left.left = new PreTree.Node(4);
head.left.right = new PreTree.Node(5);
head.right.left = new PreTree.Node(6);
head.right.right = new PreTree.Node(7);
head.left.left.left = new PreTree.Node(8);
TreeNode treeNode = new TreeNode(Integer.MAX_VALUE);
System.out.println(isCBT(treeNode));
}
}
七:完全二叉树的节点个数
7.1:思路讲解
已知我是一个完全二叉树
那么求节点个数
拿一个普通节点来说
如果我的右子树已经到达最后一层了那么我的左子树就是满二叉树
如果我的右子树没有到最后一层,那么我的右子树肯定是整棵树的高度减一的满二叉树
然后我让我的左孩子就当作这个普通节点,递归过程!
看代码吧
7.2:Java代码
package xyz.fudongyang.basic.class_04.my;
public class Code_08_CompleteTreeNodeNumber {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static int nodeNum(Node node) {
if (node == null) {
return 0;
}
return dfs(node, 1,getLeftLevel(node,1));
}
public static int dfs(Node node, int level, int high) {
/**
* 如果是叶节点就返回
* 如果右孩子到达最大高度,则说明左孩子是满二叉树
* 如果右孩子未到最大高度,则说明右孩子是比高度少一层的满二叉树
*/
if (level == high) {
return 1;
}
if (getLeftLevel(node.right,level+1) == high){
return (1 << (high - level)) + dfs(node.right,level+1,high);
}else {
return (1 << (high - level -1)) + dfs(node.left,level+1,high);
}
}
public static int getLeftLevel(Node node, int level) {
while (node != null) {
level++;
node = node.left;
}
return level - 1;
}
public static void main(String[] args) {
Node head = new Node(1);
head.left = new Node(2);
head.right = new Node(3);
head.left.left = new Node(4);
head.left.right = new Node(5);
head.right.left = new Node(6);
System.out.println(nodeNum(head));
}
}