# Memory and arrangement of knowledge points in binary tree

## Binary tree

In computer science, a binary tree is a tree structure in which each node has at most two subtrees. Generally, subtrees are called "left subtree" and "right subtree". Left subtree and right subtree are also binary trees. The subtrees of a binary tree can be divided into left and right, and the order cannot be reversed arbitrarily.

# Binary sort tree

Binary sort tree, also known as binary search tree, binary search tree, B tree.

A binary sort tree is a binary tree with the following properties:

• If the left subtree is not empty, the values of all nodes on the left subtree are smaller than the values of its root nodes;
• If the right subtree is not empty, the values of all nodes on the right subtree are greater than or equal to the values of its root nodes;
• The left and right subtrees are also binary sorting trees. That is to say, in binary sorting tree, left subtree is smaller than node, right subtree is larger than node, recursive definition.

According to the characteristics of binary sort tree, we can know that the middle order traversal of binary sort tree must be from small to large. For example, in the above figure, the middle order traversal result is:

`1  3  4  6  7  8  13  14  19`

# Node definition of binary tree

In the form of single linked list, only from the root node to the child node, the child node does not save the parent node.

``````/**
*  Binary tree node
*/
class BinaryTreeNode<T> {
T value;
BinaryTreeNode leftNode;
BinaryTreeNode rightNode;
}``````

# Create a binary tree

There is no size difference between left and right nodes in the binary tree, so if you want to create a binary tree, you need to consider how to deal with whether a node is a left node or a right node, how to terminate a subtree and switch to another subtree. Therefore, I chose the binary sort tree. There are clear requirements for left and right nodes in the binary sort tree. The program can automatically select whether the left node or the right node according to the key value.

``````/**
* Create a binary tree
*/
public static BinaryTreeNode<Integer> createTreeWithValues(int[] values) {
BinaryTreeNode root = null;
for (int value: values) {
}
return root;
}
/**
* Add a node with value in treeNode
*/
public static BinaryTreeNode<Integer> addTreeNode(BinaryTreeNode<Integer> treeNode, int value) {
if (treeNode == null) {
treeNode = new BinaryTreeNode<>();//Create node
treeNode.value = value;
} else {
if (value <= treeNode.value) {//Compare left and right nodes
} else {
}
}
return treeNode;
}``````

# Traversal of binary tree

According to the definition of binary sort tree, we can know that when looking for an element:

• First compare it with the root node, and return if it is equal; or if the root node is empty, it means that the tree is empty, and also return;
• If it is smaller than the root node, recursively search from the left subtree of the root;
• If it is larger than the root node, recursively search from the right subtree of the root.

This is a simple binary search. It's just different from binary search.

The performance of a binary tree depends on the number of layers of the binary tree:

• The best case is O(logn), which exists in the case of complete binary tree, and its access performance is similar to half search;
• The worst case is O(n). For example, all nodes of the inserted element have no left subtree (right subtree). In this case, all nodes of the binary tree need to be traversed once. ``````/**
* Middle root ergodic
*/
public static void inOrderTraverseTree(BinaryTreeNode<Integer> rootNode) {
if (rootNode != null) {
//Left middle right, middle root traversal
inOrderTraverseTree(rootNode.leftNode);
//Middle left right, root traversal first
System.out.println(" " + rootNode.value + " ");
//Left right middle, back root traversal
inOrderTraverseTree(rootNode.rightNode);
}
}``````

This is the code of root traversal in a break. First root traversal and then root traversal just adjust the order of the above lines of code.

# Binary tree node deletion

The insertion operation is similar to the search operation, while the deletion is a bit more complex. It needs to be classified according to the node deletion:

• If the node to be deleted happens to be a leaf node, it is Ok to delete it directly;
• If the node to be deleted has children, you need to establish the relationship between the parent node and the child node:

• If there is only a left child or a right child, just move the child up to the position to be deleted;
• If you have two children, you need to select an appropriate child node as the new root node, which is called the inheritance node. (the new node needs to be larger than all the left subtrees and smaller than the right subtrees. We can choose the largest node in the left subtree or the smallest node in the right subtree.)

``````/**
* Binary tree search
*/
public static BinaryTreeNode<Integer> search(BinaryTreeNode<Integer> rootNode, int value) {
if (rootNode != null) {
if (rootNode.value == value){
return rootNode;
}
if (value > rootNode.value) {
return search(rootNode.rightNode, value);
} else {
return search(rootNode.leftNode, value);
}
}
return rootNode;
}

/**
* Find the parent of the value node
*/
public static BinaryTreeNode<Integer> searchParent(BinaryTreeNode<Integer> rootNode, int value) {
//If the current node is null, or the current node is the root node. Return null
if (rootNode == null || rootNode.value == value) {
return null;
} else {
//If the left or right son of the current node is equal to value, the current node will be returned.
if (rootNode.leftNode != null && value == (Integer)rootNode.leftNode.value ||
rootNode.rightNode != null && value == (Integer)rootNode.rightNode.value) {
return rootNode;
}
//Determine the location of the node to be searched,
if (value > rootNode.value && rootNode.rightNode != null) {
return searchParent(rootNode.rightNode, value);
} else {
return searchParent(rootNode.leftNode, value);
}
}
}

/**
* Delete the node with value in the binary tree with rootNode as root node
*/
public static BinaryTreeNode<Integer> delete(BinaryTreeNode<Integer> rootNode, int value) {
//Determine whether the deleted node is the root node
if (rootNode == null && rootNode.value == value) {
rootNode = null;
return rootNode;
}
//Find the parent of the deleted node
BinaryTreeNode<Integer> parentNode = searchParent(rootNode, value);
//The parent node cannot be found, indicating that there is no corresponding node in the binary tree
if (parentNode == null) {
return rootNode;
}
BinaryTreeNode<Integer> deleteNode = search(rootNode, value);
if (deleteNode == null) {
return rootNode;
}
//Node to be deleted, leaf node
if (deleteNode.leftNode == null && deleteNode.rightNode == null) {
deleteNode = null;
if (parentNode.leftNode != null && value == (Integer)parentNode.leftNode.value) {
parentNode.leftNode = null;
} else {
parentNode.rightNode = null;
}
}
//Only the left subtree inherits the location of the node to be deleted
else if (deleteNode.rightNode == null) {
if (parentNode.leftNode != null && value == (Integer)parentNode.leftNode.value) {
parentNode.leftNode = deleteNode.leftNode;
} else {
parentNode.rightNode = deleteNode.leftNode;
}
}
//Only the right subtree inherits the location of the node to be deleted
else if (deleteNode.leftNode == null) {
if (parentNode.leftNode != null && value == (Integer)parentNode.leftNode.value) {
parentNode.leftNode = deleteNode.rightNode;
} else {
parentNode.rightNode = deleteNode.rightNode;
}
}
//The nodes to be deleted include both left Haizi and right child. We need to select the node inheritance of a facility. We select the rightmost node in the left subtree
else {
BinaryTreeNode<Integer> tmpDeleteNode = deleteNode;
BinaryTreeNode<Integer> selectNode = tmpDeleteNode.leftNode;
if (selectNode.rightNode == null) {
selectNode.rightNode = deleteNode.rightNode;
} else {
//Find the rightmost node in the left subtree of the deleteNode, that is, the largest node
while (selectNode.rightNode != null) {
tmpDeleteNode = selectNode;
selectNode = selectNode.rightNode;
}
//Assign the left subtree of the selected inherited node to the right subtree of the parent node
tmpDeleteNode.rightNode = selectNode.leftNode;
//Inheritance node inherits left and right subtrees to be deleted
selectNode.leftNode = deleteNode.leftNode;
selectNode.rightNode = deleteNode.rightNode;
}
//Inherit the selected inherited node (delete the corresponding node)
if (parentNode.leftNode != null && value == (Integer)parentNode.leftNode.value) {
parentNode.leftNode = selectNode;
} else {
parentNode.rightNode = selectNode;
}
}
return rootNode;
}``````

# Test code

``````public static void main(String[] args) {
int[] array = new int[]{8,3,19,1,6,14,4,7};
//Create a binary tree
BinaryTreeNode root = createTreeWithValues(array);
//Middle root ergodic
inOrderTraverseTree(root);
System.out.println();
//Insert 13
//Middle root ergodic
inOrderTraverseTree(root);
//Delete node with value=3
delete(root, 3);
System.out.println();
//Middle heel traversal result
inOrderTraverseTree(root);

}``````

result:

`````` 1  3  4  6  7  8  14  19
1  3  4  6  7  8  13  14  19
1  4  6  7  8  13  14  19
Process finished with exit code 0``````

# The depth of binary tree

Definition of binary tree depth: a path is formed from the nodes that pass through from the root node to the leaf node, and the longest path length is the depth of the tree.

• If the root node is empty, the depth is 0;
• If left and right nodes are empty, the depth is 1;
• Recursion idea: the depth of binary tree = max (the depth of left subtree, the depth of right subtree) + 1;

``````/**
* The depth of binary tree
*/
public static int depthOfTree(BinaryTreeNode<Integer> root) {
if (root == null) {
return 0;
}
if (root.leftNode == null && root.rightNode == null) {
return 1;
}
int leftDepth = depthOfTree(root.leftNode);
int rightDepth = depthOfTree(root.rightNode);
return Math.max(leftDepth, rightDepth) + 1;
}``````

# The width of a binary tree

``````/**
* Width of binary tree: the maximum number of nodes in each layer
* @param root Root node of binary tree
* @return The width of a binary tree
*/
public static int widthOfTree(BinaryTreeNode<Integer> root) {
if (root == null) {
return 0;
}
//Maximum width of current binary tree = root node
int maxWith = 1;
int currentWidth = 0;
//Queue: first in, first out. All nodes of one layer of the tree are reserved after each cycle
while (list.size() > 0) {
currentWidth = list.size();
//Traverse all nodes of the current layer and add the children of all nodes to the queue
for (int i = 0; i < currentWidth; i++) {
BinaryTreeNode<Integer> node = list.peek();
list.poll();
if (node.leftNode != null) {
}
if (node.rightNode != null) {
}
}
maxWith = Math.max(maxWith, list.size());
}
return maxWith;
}``````

# The number of nodes in a layer of a binary tree

``````/**
* The number of nodes in a layer of a binary tree
* @param rootNode Binary tree root node
* @param level layer
* @return level Number of nodes in the layer
*/
public static int numberOfNodesOnLevel(BinaryTreeNode<Integer> rootNode, int level) {
//When the binary tree does not exist or the level does not exist, the number of nodes is 0
int result = 0;
if (rootNode == null || level < 1) {
return result;
}
//level=1, is the root node, and the number of nodes is 1
if (level == 1) {
result = 1;
return result;
}
//Recursion: number of level level nodes of binary tree with node as root node=
// The number of nodes in the left subtree (level - 1) layer of node + the number of nodes in the right subtree (level - 1) layer of node
return numberOfNodesOnLevel(rootNode.leftNode, level - 1) +
numberOfNodesOnLevel(rootNode.rightNode, level - 1);
}``````

# The number of leaf nodes of binary tree

``````/**
* The number of leaf nodes of binary tree
* @param rootNode
* @return Number of leaf nodes
*/
public static int numberOfLeafsInTree(BinaryTreeNode<Integer> rootNode) {
int result = 0;
if (rootNode == null) {
return result;
}
//rootNode has no child nodes, so the root node is leaf node result=1;
if (null == rootNode.leftNode && null == rootNode.rightNode) {
result = 1;
return result;
}
//Recursion: leaf node of root = leaf node of left subtree of node + leaf node of right subtree of node
return numberOfLeafsInTree(rootNode.leftNode) + numberOfLeafsInTree(rootNode.rightNode);
}``````

# Maximum distance of binary tree (diameter of binary tree)

Any two nodes in a binary tree have only one path. The length of this path is called the distance between the two nodes. The maximum distance between all nodes in a binary tree is the diameter of the binary tree.
There is a solution to divide the maximum distance into three cases:

• These two nodes are respectively on the left and right subtrees of the root node. The path between them must pass through the root node, and they must be the farthest leaf node on the left and right subtrees of the root node (their distance to the root node = the depth of the left and right subtrees).
• These two nodes are all on the left subtree
• These two nodes are all on the right subtree
To sum up, as long as the maximum value of these three cases is taken, it is the diameter of the binary tree.

``````**
* The maximum distance (diameter) of a binary tree
* @param rootNode Root node
* @return Maximum distance
*/
public static int maxDistanceOfTree(BinaryTreeNode<Integer> rootNode) {
if (rootNode == null) {
return 0;
}
//1. The longest distance through the root node: distance = left subtree depth + right subtree depth
int distance = depthOfTree(rootNode.leftNode) + depthOfTree(rootNode.rightNode);
//2. The longest distance is on the left subtree of the root node, that is, the longest distance to calculate the left subtree
int disLeft = maxDistanceOfTree(rootNode.leftNode);
//3. The farthest distance is on the right subtree of the root node, that is, the farthest distance to calculate the right subtree
int disRight = maxDistanceOfTree(rootNode.rightNode);
return Math.max(distance, Math.max(disLeft, disRight));
}``````

The efficiency of this scheme is low, because the depth and the longest distance of the calculation subtree are recursive separately, and there is a case of repeated recursive traversal. In fact, one recursion can calculate the depth and the longest distance respectively, so there is a second scheme:

``````class TreeNodeProperty{
int depth = 0;
int distance = 0;
}
public static int maxDistanceOfTree2(BinaryTreeNode<Integer> rootNode) {
if (rootNode == null) {
return 0;
}
return propertyOfTreeNode(rootNode).distance;
}

public static TreeNodeProperty propertyOfTreeNode(BinaryTreeNode<Integer> rootNode) {
if (rootNode == null) {
return new TreeNodeProperty();
}
TreeNodeProperty left = propertyOfTreeNode(rootNode.leftNode);
TreeNodeProperty right = propertyOfTreeNode(rootNode.rightNode);
TreeNodeProperty p = new TreeNodeProperty();
//Depth of the current node's tree = left subtree depth + right subtree depth + 1; (root node also accounts for one depth)
p.depth = Math.max(left.depth, right.depth) + 1;
p.distance = Math.max(Math.max(left.distance, right.distance), left.depth + right.depth);
return p;
}``````

# The path from a node to the root node in a binary tree

It is not only a path finding problem, but also a node finding problem.
Define a stack to store the path (not a queue, but a variable array)

• Press in the root node, and then search from the left subtree (recursively). If not, then search from the right subtree. If not, pop up the root node, and then traverse the previous node in the stack.
• If it is found, the node stored in the stack is the node through which the path passes.

``````/**
* The path from a node to the root node in a binary tree
* @param rootNode Root node
* @param treeNode node
* @return Path queue
*/
public static Stack<BinaryTreeNode> pathOfTreeNode(BinaryTreeNode<Integer> rootNode, int treeNode) {
Stack<BinaryTreeNode> pathList = new Stack<>();
isFoundTreeNode(rootNode, treeNode, pathList);
return pathList;
}

/**
* Find whether a node is in the tree
* @param rootNode Root node
* @param treeNode Nodes to find
* @param path The path from the root node to the node to be found
* @return Whether to find the node
*/
public static boolean isFoundTreeNode(BinaryTreeNode<Integer> rootNode, int treeNode,
Stack<BinaryTreeNode> path) {
if (rootNode == null) {
return false;
}
//The current node is the node to be found
if (rootNode.value == treeNode) {
return true;
}
//Push a passing node into the stack
//Find in the left subtree first
boolean find = isFoundTreeNode(rootNode.leftNode, treeNode, path);
if (!find) {
//If not, then search in the right subtree
find = isFoundTreeNode(rootNode.rightNode, treeNode, path);
}
if (!find) {
path.pop();
}
return find;
}``````

# The nearest common parent of two nodes in a binary tree

First of all, we need to understand that the root node must be the common parent node (not necessarily the nearest) of any two nodes in the binary tree, so the nearest common parent node of two nodes in the binary tree must be on the path from the root node to this node. So we can find the path from the root node to these two nodes respectively, and then find the nearest common parent node from these two paths.

``````/**
* The nearest common node of two nodes of binary tree species
* @param rootNode Root node
* @param nodeA First node
* @param nodeB Second node
* @return Nearest public node
*/
public static int parentOfNode(BinaryTreeNode<Integer> rootNode, int nodeA, int nodeB) {
if (rootNode == null) {
return -1;
}
//Two nodes are the same node
if (nodeA == nodeB) {
return nodeA;
}
//One of the points is the root node
if (rootNode.value == nodeA || rootNode.value == nodeB) {
return rootNode.value;
}
//Path from root node to node A
Stack<BinaryTreeNode> pathA = pathOfTreeNode(rootNode, nodeA);
//Path from root node to node B
Stack<BinaryTreeNode> pathB = pathOfTreeNode(rootNode, nodeB);
//The node you are looking for is not in the tree
if (pathA.size() == 0 || pathB.size() == 0) {
return -1;
}
//Change the data structure of the path to an array
int[] arrayA = new int[pathA.size()];
int[] arrayB = new int[pathB.size()];
for (int i = pathA.size() - 1; i >= 0; i--){
arrayA[i] = (int) pathA.pop().value;
}
for (int i = pathB.size() - 1; i >= 0; i--) {
arrayB[i] = (int) pathB.pop().value;
}
//If the i+1 node is different, then the i node is the nearest public node
for (int i = 0; i < arrayA.length - 1 && i < arrayB.length - 1; i++) {
if (arrayA[i + 1] != arrayB[i + 1]) {
return arrayA[i];
}
if (i + 1 == arrayA.length - 1) {
return arrayA[arrayA.length - 1];
}
if (i + 1 == arrayB.length - 1) {
return arrayB[arrayB.length - 1];

}
}
return -1;
}``````

# Path between two nodes in a binary tree

Derived from finding the most recent common parent.

``````/**
* Path between two nodes in a binary tree
* @param rootNode Root node
* @param nodeA First node
* @param nodeB Second node
* @return route
*/
public static List<Integer> pathFromNode(BinaryTreeNode<Integer> rootNode, int nodeA, int nodeB) {
if (rootNode == null) {
return null;
}
List<Integer> result = new ArrayList<>();
if (nodeA == nodeB) {
return result;
}
//Path from root node to node A
Stack<BinaryTreeNode> pathA = pathOfTreeNode(rootNode, nodeA);
//Path from root node to node B
Stack<BinaryTreeNode> pathB = pathOfTreeNode(rootNode, nodeB);
if (rootNode.value == nodeB) {
pathA.forEach(new Consumer<BinaryTreeNode>() {
@Override
public void accept(BinaryTreeNode binaryTreeNode) {
}
});
return result;
}
if (rootNode.value == nodeA) {
pathB.forEach(new Consumer<BinaryTreeNode>() {
@Override
public void accept(BinaryTreeNode binaryTreeNode) {
}
});
return result;
}
//The node you are looking for is not in the tree
if (pathA.size() == 0 || pathB.size() == 0) {
return null;
}
//Change the data structure of the path to an array
int[] arrayA = new int[pathA.size()];
int[] arrayB = new int[pathB.size()];
for (int i = pathA.size() - 1; i >= 0; i--){
arrayA[i] = (int) pathA.pop().value;
}
for (int i = pathB.size() - 1; i >= 0; i--) {
arrayB[i] = (int) pathB.pop().value;
}
//If the i+1 node is different, then the i node is the nearest public node
int lastNode = -1;
for (int i = 0; i < arrayA.length - 1 && i < arrayB.length - 1; i++) {
if (arrayA[i + 1] != arrayB[i + 1]) {
lastNode = i;
break;
}
if (i + 1 == arrayA.length - 1) {
lastNode = arrayA.length - 1;
break;
}
if (i + 1 == arrayB.length - 1) {
lastNode = arrayB.length - 1;
break;
}
}
for (int i = arrayA.length - 1; i >= lastNode; i--) {
}
for (int i = lastNode + 1; i < arrayB.length; i++) {
}
return result;
}``````

# Flip binary tree

Turning over a binary tree, also known as finding the image of a binary tree, is to transpose the left and right subtrees of the binary tree (recursive, of course)

``````/**
* Flip binary tree
* @param rootNode Root node
* @return Inverted binary tree
*/
public static BinaryTreeNode invertBinaryTree(BinaryTreeNode<Integer> rootNode) {
if (rootNode == null) {
return null;
}
//Only one root node
if (rootNode.leftNode == null && rootNode.rightNode == null) {
return rootNode;
}
invertBinaryTree(rootNode.leftNode);
invertBinaryTree(rootNode.rightNode);
BinaryTreeNode tempNode = rootNode.leftNode;
rootNode.leftNode = rootNode.rightNode;
rootNode.rightNode = tempNode;
return rootNode;
}``````

# Complete binary tree

``````A Complete Binary Tree (CBT) is a binary tree in which every level,
except possibly the last, is completely filled, and all nodes
are as far left as possible.``````

In other words, the complete binary tree from the root node to the penultimate layer satisfies the perfect binary tree, the last layer can not be completely filled, and its leaf nodes are aligned to the left.

For example: According to the definition of the complete binary tree in Li Chunbao's data structure tutorial, it is defined as: "at most, the degree of the bottom two layers of nodes in the binary tree is less than two, and the leaf nodes of the bottom one layer are all arranged on the leftmost position of the layer at one time, such a binary tree is called a complete binary tree".

characteristic

• Leaf nodes can only appear in the two largest layers;
• For the leaf nodes in the largest layer, they are all arranged in the leftmost position of the layer at one time;
• If there is a leaf node with a degree of one, there may only be one, and the node has only left children and no children.

The priority breadth traversal algorithm is adopted, and the queue is entered from top to bottom, from left to right. We can set a flag bit flag. When the subtree satisfies the full binary tree, set flag=true. When flag=ture and the node breaks the condition of a complete binary tree, it is not a complete binary tree.

``````/**
* Is it a complete binary tree
* Complete binary tree: if the height of the binary tree is h, the number of nodes in all layers, except the H layer, reaches the maximum. The H layer has leaf nodes, and the leaf nodes are arranged from left to right
* @param rootNode Root node
* @return Is it a complete binary tree
*/
public static boolean isCompleteBinaryTree(BinaryTreeNode<Integer> rootNode) {
if (rootNode == null) {
return false;
}
//If both the left and right subtrees are empty, they are completely binary trees
if (rootNode.leftNode == null && rootNode.rightNode == null) {
return true;
}
//If the left subtree is empty and the right subtree is not empty, it is not a complete binary tree
if (rootNode.leftNode == null && rootNode.rightNode != null) {
return false;
}
//Whether the binary tree is satisfied
boolean isComplete = false;
while (queue.size() > 0) {
BinaryTreeNode<Integer> node = queue.pop();
//If the left subtree is empty and the right subtree is not empty, it is not a complete binary tree
if (node.leftNode == null && node.rightNode != null) {
return false;
}
//The previous nodes satisfy the complete binary tree. If there are children nodes, they are not complete binary trees
if (isComplete && (node.leftNode != null || node.rightNode != null)) {
return false;
}
//If the right subtree is empty, the complete binary tree has been satisfied
if (node.rightNode == null) {
isComplete = true;
}
//Pressing child nodes into
if (node.leftNode != null) {
}
if (node.rightNode != null) {
}
}
return isComplete;
}``````

# Judge whether the binary tree is full

A full binary tree is defined as a binary tree in which every node has left and right cotyledons and the leaf node is at the bottom except the leaf node

A characteristic of a full binary tree is that the number of leaves = 2 ^ (depth-1), so we can judge whether a binary tree is a full binary tree according to this characteristic.

``````/**
* Is it full of binary trees
* Full binary tree: a binary tree in which every node has left and right cotyledons and the leaf node is at the bottom except the leaf node
* @param rootNode Root node
* @return Is it full of binary trees
*/
public static boolean isFullBinaryTree(BinaryTreeNode<Integer> rootNode) {
if (rootNode == null) {
return false;
}
int depth = depthOfTree(rootNode);
int leafNum = numberOfLeafsInTree(rootNode);
if (leafNum == Math.pow(2, (depth - 1))) {
return true;
}
return false;
}``````

# balanced binary tree

Balanced binary tree is defined as: it is an empty tree or the absolute value of the height difference between its left and right two subtrees is not more than 1, and both the left and right subtrees are a balanced binary tree. Balanced binary tree is also called AVL tree.

``````/**
* Is binary tree balanced
* @param rootNode Root node
* @return Is binary tree balanced
*/
static int height;
public static boolean isAVLBinaryTree(BinaryTreeNode<Integer> rootNode) {
if (rootNode == null) {
height = 0;
return true;
}
if (rootNode.leftNode == null && rootNode.rightNode == null) {
height = 1;
return true;
}
boolean isAV<center>![LLeft = isAVLBinaryTree(rootNode.leftNode);
int heightLeft = height;
boolean isAVLRight = isAVLBinaryTree(rootNode.rightNode);
int heightRight = height;
height = Math.max(heightLeft, heightRight) + 1;
return isAVLLeft && isAVLRight && Math.abs(heightLeft - heightRight) <= 1;
}``````

Originally I wanted to see the red black tree, but I forgot about the knowledge about the tree. I took the time to look at the knowledge about the binary tree these days, and sorted it out as notes.
Code
Reference article:
Binary tree - you have to understand! (implementation of binary tree correlation algorithm iOS)