题目一
实现二叉树的先序、中序、后序遍历,包括递归方式和非递归方式
递归方式实现
//先序遍历
public static void preOrderRecur(Node head){
if (head == null){
return;
}
System.out.println(head.value + " ");
preOrderRecur(head.left);
preOrderRecur(head.right);
}
//中序遍历
public static void inOrderRecur(Node head){
if (head == null){
return;
}
inOrderRecur(head.left);
System.out.println(head.value + " ");
inOrderRecur(head.right);
}
//后序遍历
public static void posOrderRecur(Node head) {
if (head == null){
return;
}
posOrderRecur(head.left);
System.out.println(head.value + " ");
posOrderRecur(head.right);
}
非递归方式实现
//非递归方式先序遍历
public static void preOrderUnRecur(Node head){
System.out.println("pre-order");
if (head != null){
Stack<Node> stack = new Stack<>();
stack.add(head);
while (!stack.isEmpty()){
head = stack.pop();
System.out.println(head.value + " ");
if (head.right != null){
stack.push(head.right);
}
if (head.left != null){
stack.push(head.left);
}
}
}
System.out.println();
}
//非递归方式中序遍历
public static void inOrderUnRecur(Node head){
System.out.println("pre-order");
if (head != null){
Stack<Node> stack = new Stack<>();
stack.add(head);
while (!stack.isEmpty() || head != null){
if (head != null){
stack.push(head);
head = head.left;
}else {
head = stack.pop();
System.out.println(head.value + " ");
head = head.right;
}
}
}
System.out.println();
}
//非递归方式后序遍历
public static void posOrderUnRecur(Node head) {
System.out.println("pre-order");
if (head != null){
Stack<Node> s1 = new Stack<>();
Stack<Node> s2 = new Stack<>();
s1.push(head);
while (!s1.isEmpty()){
head = s1.pop();
s2.push(head);
if (head.left != null){
s1.push(head.left);
}
if (head.right != null){
s1.push(head.right);
}
}
while (!s2.isEmpty()){
System.out.println(s2.pop().value+" ");
}
}
System.out.println();
}
题目二
如何直观的打印一颗二叉树
题目三
思路:找到node的后继节点,当node右子树存在时,node的后继节点一定是右子树的最左的节点,当node没有右子树,后继节点就是以node为左子树最后一个节点的父节点
代码部分
public static class Node{
public int value;
public Node left;
public Node right;
public Node parent;
public Node(int data){
this.value = data;
}
}
/**
* 给定树中的某一个节点,寻找后继 默认是中序遍历
* @param node
* @return
*/
public static Node getSuccessorNode(Node node){
if (node == null){
return node;
}
if (node.right != null){
//有右孩子的情况下,直接找到右子树最左的节点
return getLeftMost(node.right);
}else {
//当前节点没有右孩子,所以向上寻找后继
Node parent = node.parent;
//parent != null防止越界
while (parent != null && parent.left != node){
node = parent;
parent = node.parent;
}
return parent;
}
}
private static Node getLeftMost(Node node) {
if (node == null){
return node;
}
while (node.left != null){
node = node.left;
}
return node;
}
题目四
介绍二叉树的序列化和反序列化
1.先序方式序列化(中左右)
思路:用一个字符串存储每一个节点的值,值与值之间使用!分割,空值用#代替
/**
* @author :LY
* @date :Created in 2021/4/2 11:03
* @modified By:
*/
public class 二叉树序列化 {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int data){
this.value = data;
}
}
/**
* 先序 序列化二叉树
* @param head
* @return
*/
public static String serialByPre(Node head){
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[] values = preStr.split("!");
Queue<String> queue = new LinkedList<>();
for (int i = 0; i != values.length ; i++) {
queue.offer(values[i]);
}
return reconByPreOrder(queue);
}
/**
* 先序 反序列化
* @param queue
* @return
*/
private static Node reconByPreOrder(Queue<String> queue) {
String value = queue.poll();
if (value.equals("#")){
return null;
}
Node head = new Node(Integer.valueOf(value));
head.left = reconByPreOrder(queue);
head.right = reconByPreOrder(queue);
return head;
}
/**
* 层级序列化
* @param head
* @return
*/
public static String serialByLevel(Node head){
if (head == null){
return "#!";
}
String res = head.value + "!";
Queue<Node> queue = new LinkedList<>();
queue.offer(head);
while (!queue.isEmpty()){
//从队列头部拿出
head = queue.poll();
if (head.left != null){
res += head.left.value+"!";
queue.offer(head.left);
}else {
res += "#!";
}
if (head.right != null){
res += head.right.value + "!";
queue.offer(head.right);
}else {
res += "#!";
}
}
return res;
}
/**
* 层级反序列化
* @param levelStr
* @return
*/
public static Node reconByLevelString(String levelStr){
String[] values = levelStr.split("!");
int index = 0;
Node head = generateNodeByString(values[index++]);
Queue<Node> queue = new LinkedList<>();
if (head != null){
queue.offer(head);
}
Node node = null;
while (!queue.isEmpty()){
node = queue.poll();
node.left = generateNodeByString(values[index++]);
node.right = generateNodeByString(values[index++]);
if (node.left != null){
queue.offer(node.left);
}
if (node.right != null){
queue.offer(node.right);
}
}
return head;
}
private static Node generateNodeByString(String value) {
if (value.equals("#")){
return null;
}
return new Node(Integer.valueOf(value));
}
}
题目六
判断一颗二叉树是否是平衡二叉树
平衡二叉树:对于在这树的任何一个节点,它左子树和右子树的高度差不超过1
使用递归解决:
-
- 判断左树是否平衡
- 判断右树是否平衡
- 左树平衡计算高度
- 右树平衡计算高度
- 计算左右高度差是否超过1
所以递归函数需要返回两个值 ,是否平衡以及树的高度
/**
* @author :LY
* @date :Created in 2021/4/8 10:52
* @modified By:
*/
public class 判断平衡二叉树 {
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 class ReturnData{
public boolean isB;
public int h;
public ReturnData(boolean isB,int h){
this.isB = isB;
this.h = h;
}
}
public static boolean isB(Node head){
return process(head).isB;
}
public static ReturnData process(Node head){
if (head == null)
return new ReturnData(true,0);
ReturnData leftData = process(head.left);
if (!leftData.isB)
return new ReturnData(false,0);
ReturnData rightData = process(head.right);
if (!rightData.isB)
return new ReturnData(false,0);
if (Math.abs(leftData.h-rightData.h)>1){
return new ReturnData(false,0);
}
return new ReturnData(true,Math.max(leftData.h,rightData.h)+1);
}
题目七
判断一颗树是否是搜索二叉树、判断一棵树是否是完全二叉树
搜索二叉树:对于二叉树上的任何一个节点,它的左子树都比它小,右子树都比它大
完全二叉树:判断逻辑,二叉树按层遍历,如果一个节点有右孩子没有左孩子,一定不是完全二叉树,直接返回false,第二 如果一个节点不是左右两个孩子都全,这样都话,后面遍历的节点必须是叶节点(没有子节点的)才是完全二叉树
判断搜索二叉树代码
public static boolean isBST1(Node head){
if (head == null){
return true;
}
boolean res = true;
Node pre = null;
Node cur1 = head;
Node cur2 = null;
while (cur1 != null){
cur2 = cur1.left;
if (cur2 != null){
while (cur2.right != null && cur2.right != cur1){
cur2 = cur2.right;
}
if (cur2.right == null){
cur2.right = cur1;
cur1 = cur1.left;
continue;
}else {
cur2.right = null;
}
}
if (pre != null && pre.value > cur1.value){
res = false;
}
pre = cur1;
cur1 = cur1.right;
}
return res;
}
//判断是否是搜索二叉树
public static boolean isBST2(Node head){
if (head != null){
int pre = Integer.MIN_VALUE;
Stack<Node> stack = new Stack<>();
stack.push(head);
while (!stack.isEmpty() && head != null){
if (head != null){
stack.push(head);
head = head.left;
}else {
head = stack.pop();
if (head.value<pre){
return false;
}
pre = head.value;
System.out.println(head.value + " ");
head = head.right;
}
}
}
return true;
}
判断完全二叉树
//判断是否是完全二叉树
public static boolean isCBT(Node head){
if (head == null){
return true;
}
Queue<Node> queue = new LinkedList<>();
boolean leaf = false;
Node l = null;
Node r = null;
queue.offer(head);
while (!queue.isEmpty()){
head = queue.poll();
l = head.left;
r = head.right;
if ((leaf && (l != null || r != null)) || (l == null && r != null)){
return false;
}
if (l != null){
queue.offer(l);
}
if (r != null){
queue.offer(r);
}else {
leaf = true;
}
}
return true;
}
题目八
已知一颗完全二叉树,求其节点的个数
要求:时间复杂度低于O(N),N为这颗树的节点个数
思路:首先需要知道一个结论,如果一颗树是满二叉树,它的高度是L,那么它的节点个数就是2的L次方减1,我们利用这个公式来加速。
完全二叉树,我们首先直接遍历到树的左边界,拿到它的高度(o(logn)),还需要记录到了树的哪一层,然后我们可以遍历到根节点的右子树的左边界,看看是否到了我们上面记录的层树,
1 . 如果到了,证明根节点的左子树的满二叉树,此时直接可以根据公式求出左树的节点数,然后递归求出右树的节点数
2 . 如果没到,那么证明右子树是满二叉树,只不过高度为L-1,算出右子树,再递归算左子树
O(Log(N)的平方)
/**
* @author :LY
* @date :Created in 2021/4/12 10:31
* @modified By:
*/
public class 计算完全二叉树节点数量 {
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 head){
if (head == null){
return 0;
}
return bs(head,1,mostLeftLevel(head,1));
}
/**
*
* @param node 当前节点
* @param level 当前节点在第几层
* @param h 当前树的高度
* @return 返回节点个数
*/
public static int bs(Node node,int level,int h){
if (level == h){
return 1;
}
//走到右边最左节点,
if (mostLeftLevel(node.right,level + 1) == h){
//1 << (h - level)相当于2的h-level次方
return (1 << (h - level) + bs(node.right,level + 1,h));
}else {
return (1 << (h - level -1) + bs(node.left,level + 1,h));
}
}
//查找最左节点的层数
private static int mostLeftLevel(Node node, int level) {
while (node != null){
level ++;
node = node.left;
}
return level -1;
}
}