package com.zuoshen.jichurumen.class05;
import java.util.*;
/**
* @author ShiZhe
* @create 2022-02-28 20:41
*/
public class code01 {
/**
* 二叉树节点
*/
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
/**
* 二叉树前序递归遍历
* @param head
*/
public static void preOrderRecur(Node head) {
if (head == null) {
return;
}
System.out.print(head.value + " ");
preOrderRecur(head.left);
preOrderRecur(head.right);
}
/**
* 二叉树前序非递归遍历
* 通过栈来实现
* 先右后左
* @param head
*/
public static void preOrderUnRecur(Node head) {
System.out.print("pre-order: ");
if (head != null) {
Stack<Node> stack = new Stack<Node>();
stack.add(head);
while (!stack.isEmpty()) {
head = stack.pop();
System.out.print(head.value + " ");
if (head.right != null) {
stack.push(head.right);
}
if (head.left != null) {
stack.push(head.left);
}
}
}
System.out.println();
}
/**
* 二叉树中序递归遍历
* @param head
*/
public static void inOrderRecur(Node head) {
if (head == null) {
return;
}
inOrderRecur(head.left);
System.out.print(head.value + " ");
inOrderRecur(head.right);
}
/**
* 二叉树中序非递归遍历
* 通过栈来实现
* 先放左,再放右
* @param head
*/
public static void inOrderUnRecur(Node head) {
System.out.print("in-order: ");
if (head != null) {
Stack<Node> stack = new Stack<>();
while (!stack.isEmpty() || head != null) {
if (head != null) {
stack.push(head);
head = head.left;
} else {
head = stack.pop();
System.out.print(head.value + " ");
head = head.right;
}
}
}
System.out.println();
}
/**
* 二叉树后序递归遍历
* @param head
*/
public static void posOrderRecur(Node head) {
if (head == null) {
return;
}
posOrderRecur(head.left);
posOrderRecur(head.right);
System.out.print(head.value + " ");
}
/**
* 二叉树后序递归遍历-1
* 与二叉树前序遍历类似
* @param head
*/
public static void posOrderUnRecur1(Node head) {
System.out.print("pos-order: ");
if (head != null) {
Stack<Node> s1 = new Stack<Node>();
Stack<Node> s2 = new Stack<Node>();
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.print(s2.pop().value + " ");
}
}
System.out.println();
}
/**
* 二叉树后序递归遍历-2
* 利用栈的peek()函数获取栈顶的节点
* 我们什么时候才能访问节点。有如下两种情况:
* 当前经过节点是叶子节点。
* 当前经过节点的右子节点是上一次访问的节点。
* @param head
*/
public static void posOrderUnRecur2(Node head) {
System.out.print("pos-order: ");
Stack<Node> stack = new Stack<>();
// 当前节点
Node cur = head;
// 用于记录上一次访问的节点
Node pre = null;
while (cur != null || !stack.isEmpty()) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
if (!stack.isEmpty()) {
cur = stack.pop();
// 访问节点的调节
if (cur.right == null || pre == cur.right) {
// 访问
System.out.print(cur.value + " ");
// 这一步是记录上一次访问的节点
pre = cur;
// 此处为了跳过下一次循环的访问左子节点的过程,直接进入栈的弹出阶段,因为但凡在栈中的节点,它们的左子节点都肯定被经过且已放入栈中。
cur = null;
} else { // 不访问节点的条件
// 将已弹出的根节点放回栈中
stack.push(cur);
// 经过右子节点
cur= cur.right;
}
}
}
System.out.println();
}
/**
* 二叉树最大宽度
* 使用队列
* @param head
*/
public static int getMaxWidth(Node head) {
if (head == null) {
return 0;
}
// hashMap将节点与层数绑定,通过层数的变化来计算每一层的width
HashMap<Node, Integer> levelMap = new HashMap<>();
// queue存储每层的节点
// linkedList与arrayList的区别在于linkedList使用双链表存储,而arrayList使用数组存储。
LinkedList<Node> queue = new LinkedList<>();
// 需要求的最大的width
int maxWidth = 0;
// 当前层的width
int curWidth = 0;
// 当前层数
int curLevel = 1;
// 初始化
levelMap.put(head, 1);
queue.add(head);
Node node = null;
Node left = null;
Node right = null;
while (!queue.isEmpty()) {
node = queue.poll();
left = node.left;
right = node.right;
if (left != null) {
levelMap.put(left, levelMap.get(node) + 1);
queue.add(left);
}
if (right != null) {
levelMap.put(right, levelMap.get(node) + 1);
queue.add(right);
}
if (levelMap.get(node) > curLevel) {
curWidth = 1;
curLevel = levelMap.get(node);
} else {
curWidth++;
}
maxWidth = Math.max(curWidth, maxWidth);
}
return maxWidth;
}
/**
* 判断是否是二叉搜索树,中序遍历是有序的。
* @param head
* @return
*/
public static boolean isBST(Node head) {
if (head == null) {
return true;
}
LinkedList<Node> inOrderList = new LinkedList<>();
isBSTProcess(head, inOrderList);
int pre = Integer.MIN_VALUE;
Node cur = null;
while (!inOrderList.isEmpty()) {
cur = inOrderList.poll();
if (pre >= cur.value) {
return false;
}
pre = cur.value;
}
return true;
}
/**
* BST的中序遍历
* @param node
* @param inOrderList
*/
public static void isBSTProcess(Node node, LinkedList<Node> inOrderList) {
if (node == null) {
return;
}
isBSTProcess(node.left, inOrderList);
inOrderList.add(node);
isBSTProcess(node.right, inOrderList);
}
/**
* CBT:完全二叉树,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,
* 则这棵二叉树称为完全二叉树。
* 叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。
* @param head
* @return
*/
public static boolean isCBT(Node head) {
if (head == null) {
return true;
}
LinkedList<Node> queue = new LinkedList<>();
// 判断是否为叶子结点
boolean leaf = false;
queue.add(head);
Node cur = null;
while (!queue.isEmpty()) {
cur = queue.poll();
// 左无右有返回false
// 已经出现叶子节点了,后面出现非叶子节点的返回false
if ((cur.left == null && cur.right!=null) || (leaf && (cur.left != null ||cur.right != null))) {
return false;
}
if (cur.left != null) {
queue.add(cur.left);
}
// 右边为空,则后面均为叶子结点
if (cur.right != null) {
queue.add(cur.right);
} else {
leaf = true;
}
}
return true;
}
/**
* 判断是否是平衡二叉树:左右子树的高度差的绝对值不超过1
* @param head
* @return
*/
public static boolean isBalanced(Node head) {
return process(head).isBalanced;
}
/**
* 平衡二叉树的返回数据格式
*/
public static class ReturnTypeIsBalanced {
// 当前数的高度
public int height;
// 当前数是否是平衡二叉树
public boolean isBalanced;
// 构造函数
public ReturnTypeIsBalanced(boolean isBalanced, int height) {
this.height = height;
this.isBalanced = isBalanced;
}
}
/**
* 判断是否是平衡二叉树的处理函数
* 向左数要数据,向右数要数据,比较,得到答案
* @param head
* @return
*/
public static ReturnTypeIsBalanced process(Node head) {
if (head == null) {
return new ReturnTypeIsBalanced(true, 0);
}
ReturnTypeIsBalanced leftData = process(head.left);
ReturnTypeIsBalanced rightData = process(head.right);
int height = Math.max(leftData.height, rightData.height) + 1;
boolean isBalanced = leftData.isBalanced && rightData.isBalanced &&
Math.abs(leftData.height - rightData.height) < 2;
return new ReturnTypeIsBalanced(isBalanced, height);
}
/**
* 最低公共祖先节点
* 递归遍历,寻找节点
* @param head
* @param o1
* @param o2
* @return
*/
public static Node lowestAncestor(Node head, Node o1, Node o2) {
// 发现目标节点,标记返回
if (head == null || head == o1 || head == o2) {
return head;
}
// 在左子树上找寻目标节点
Node left = lowestAncestor(head.left, o1, o2);
// 在右子树找寻目标节点
Node right = lowestAncestor(head.right, o1, o2);
// 在左子树和右子树上分别找到,则改树的头为最低公共祖先节点
if (left != null && right != null) {
return head;
}
// 有一个为空,则表示2个在同侧,返回非空节点就行
return left != null ? left : right;
}
/**
* 拥有parent指针的二叉树节点结构
*/
public static class NodeNew {
public int value;
public NodeNew left;
public NodeNew right;
public NodeNew parent;
public NodeNew(int data) {
this.value = data;
}
}
/**
* 获取某一节点的后继节点
* 在二叉树的中序遍历的序列中, node的下一个节点叫作node的后继节点。
* @param node
* @return
*/
public static NodeNew getSuccessorNode(NodeNew node) {
if (node == null) {
return node;
}
// 右子树不为空,后继节点为右子树最左节点
if (node.right != null) {
return getLeftMost(node.right);
} else {
// 右子树为空
// 当该节点为父亲节点的左子树时,该节点的后继节点就是父亲节点
// 当该节点不是父亲节点的左子树的,将父亲节点设为子节点,循环找子节点为父亲节点的左子树的父亲节点
NodeNew parent = node.parent;
while (parent.left != node && parent != null) {
node = parent;
parent = node.parent;
}
return parent;
}
}
/**
* 获取该节点最左节点
* @param node
* @return
*/
public static NodeNew getLeftMost(NodeNew node) {
if (node.left == null) {
return node;
}
while (node.left != null) {
node = node.left;
}
return node;
}
/**
* 按照先序遍历序列化二叉树
* @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;
}
/**
* 二叉树的反序列化
* @param preStr
* @return
*/
public static Node reconByPreString(String preStr) {
// 将value按照!划分出来
String[] values = preStr.split("!");
LinkedList<String> queue = new LinkedList<String>();
// 放入队列
for (int i = 0; i != values.length; i++) {
queue.offer(values[i]);
}
return reconPreOrder(queue);
}
/**
* 递归调用
* @param queue
* @return
*/
public static Node reconPreOrder(LinkedList<String> queue) {
String value = queue.poll();
// #表示空
if (value.equals("#")) {
return null;
}
Node head = new Node(Integer.valueOf(value));
head.left = reconPreOrder(queue);
head.right = reconPreOrder(queue);
return head;
}
/**
* 对折纸张的折痕问题
* 看做一个中序遍历二叉树的问题
* @param N
*/
public static void printAllFolds(int N) {
printProcess(1, N, true);
}
/**
* 题意是从上至下,二叉树就需要先右后左
* 右是下 down,左是上 up
* @param i 当前层数,也是当前次数
* @param N 总层数,也是总次数
* @param down
*/
public static void printProcess(int i, int N, boolean down) {
if (i > N) {
return;
}
printProcess(i + 1, N, true);
System.out.println(down ? "down " : "up ");
printProcess(i + 1, N, false);
}
public static void main(String[] args) {
Node head = new Node(5);
head.left = new Node(3);
head.right = new Node(8);
head.left.left = new Node(2);
Node node2 = new Node(4);
head.left.right = node2;
Node node1 = new Node(1);
head.left.left.left = node1;
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);
head.left.right.left = new Node(12);
head.left.right.right = new Node(13);
head.left.left.right = new Node(14);
Node head1 = new Node(9);
head1.left = new Node(3);
head1.left.left = new Node(4);
// 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);
// maxWidth
int maxWidth = getMaxWidth(head);
System.out.println(maxWidth);
// isBST
boolean bst = isBST(head);
System.out.println(bst);
// isBalanced
boolean balanced = isBalanced(head);
System.out.println(balanced);
boolean balanced1 = isBalanced(head1);
System.out.println(balanced1);
// 最低公共祖先
Node node = lowestAncestor(head, node1, node2);
System.out.println(node.value);
// 后继节点
NodeNew head2 = new NodeNew(6);
head2.parent = null;
head2.left = new NodeNew(3);
head2.left.parent = head2;
head2.left.left = new NodeNew(1);
head2.left.left.parent = head2.left;
head2.left.left.right = new NodeNew(2);
head2.left.left.right.parent = head2.left.left;
head2.left.right = new NodeNew(4);
head2.left.right.parent = head2.left;
head2.left.right.right = new NodeNew(5);
head2.left.right.right.parent = head2.left.right;
head2.right = new NodeNew(9);
head2.right.parent = head2;
head2.right.left = new NodeNew(8);
head2.right.left.parent = head2.right;
head2.right.left.left = new NodeNew(7);
head2.right.left.left.parent = head2.right.left;
head2.right.right = new NodeNew(10);
head2.right.right.parent = head2.right;
NodeNew test = head2.left.left;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
// 序列化与反序列化
String s = serialByPre(head);
String s1 = serialByPre(head1);
System.out.println(s);
System.out.println(s1);
Node node3 = reconByPreString(s);
Node node4 = reconByPreString(s1);
System.out.println(node3.value);
System.out.println(node4.value);
}
}