# [key and difficult points] [data structure 01] binary sort tree and balanced binary tree

Keywords: data structure

# 1, Binary sort tree

## 1. Introduction

Binary Sort Tree (BST), for any non leaf node of the Binary Sort Tree, the value of the left child node is required to be smaller than that of the current node, and the value of the right child node is required to be larger than that of the current node. If you have the same value, you can put the node on the left child node or the right child node

## 2. Create

1. Take the first value of the array as the root node
2. If the next value is smaller than the root node, it recurses to the left subtree until the current node has no left child node, so it is the left child node of the current node
3. If the next value is larger than the root node, it recurses to the right subtree until the current node has no right child node, so it is the right child node of the current node
4. Repeat the above two steps until the array traversal is completed

## 3. Delete node

Delete leaf node

1. Find the targetNode to delete
2. Find the parent node of targetNode
3. Determines whether the targetNode is the left child node or the right child node of the parent
4. Delete according to conditions
Left child node: parent.left = null
Right child node: parent.right = null

Delete a node with only one child node

1. Find the targetNode to delete
2. Find the parent node of targetNode
3. Determine whether the child node of the targetNode is A left child node or A right child node (the left is marked as A and the right is marked as B)
4. Determine whether the target is the left child node or the right child node of the parent (the left is marked as 1 and the right is marked as 2)
5. Delete according to conditions
A1: parent.left = targetNode.left
A2: parent.right = targetNode.left
B1: parent.left = targetNode.right
B2: parent.right = targetNode.right

Delete a node with two child nodes

1. Find the targetNode to delete
2. Find the parent node of targetNode
3. Recursively find the smallest nearest node minVal in the leaf node in the right subtree of the targetNode
4. Create a temporary variable temp, temp = minVal
5. Delete minVal
6. targetNode.value =temp

## 4. Code implementation

```package com.sisyphus.BinaryTree;

public class BinarySortTreeDemo {
public static void main(String[] args) {
int[] arr = {7,3,10,12,5,1,9,0};
BinarySortTree binarySortTree = new BinarySortTree();
for(int i : arr){
}

System.out.println("Middle order traversal:");
binarySortTree.infixOrder();

binarySortTree.delNode(10);
System.out.println("After deleting a node");
binarySortTree.infixOrder();
}
}

class Node{
int value;
Node left;
Node right;

public Node(int value){
this.value = value;
}

@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}

public Node search(int value){
if(value ==this.value){
return this;
}else if(value < this.value){
if(this.left == null){
return null;
}
return this.left.search(value);
}else{
if(this.right == null){
return null;
}
return this.right.search(value);
}
}

public Node searchParent(int value){
if((this.left != null && this.left.value == value) || (this.right != null && this.right.value == value)){
return this;
}else{
if(value < this.value && this.left != null){
return this.left.searchParent(value);
}else if(value > this.value && this.right != null){
return this.right.searchParent(value);
}else{
return null;
}
}
}

if(node == null){
return;
}

if(node.value < this.value){
if(this.left == null){
this.left = node;
}else{
}
}else{
if(this.right == null){
this.right = node;
}else{
}
}
}

//Medium order traversal
public void infixOrder(){
if(this.left != null){
this.left.infixOrder();
}
System.out.println(this);
if (this.right != null){
this.right.infixOrder();
}
}
}

class BinarySortTree{
private Node root;

public Node search(int value){
if(root == null){
return null;
}else{
return root.search(value);
}
}

public Node searchParent(int value){
if(root == null){
return null;
}else{
return root.searchParent(value);
}
}

public int delReturnMin(Node node){
while(node.left != null){
node = node.left;
}
delNode(node.value);
return node.value;
}

if(root == null){
root = node;
}else{
}
}

//Medium order traversal
public void infixOrder(){
if(root == null){
System.out.println("The tree is empty and cannot be traversed");
}else{
root.infixOrder();
}
}

//Delete Vertex
public void delNode(int value){
if(root == null){
return;
}else{
Node targetNode = root.search(value);

if(targetNode == null){
return;
}

Node parent = searchParent(value);

//Delete leaf node
if(targetNode.left == null && targetNode.right == null){
if(parent.left != null && parent.left.value == value){
parent.left = null;
}else{
parent.right = null;
}
}
//Delete a node with two child nodes
else if(targetNode.left != null && targetNode.right != null){
int minVal = delReturnMin(targetNode.right);
targetNode.value = minVal;
}
//Delete a node with only one child node
else{
if(targetNode.left != null){
if(parent != null){
if(parent.left.value == value){
parent.left = targetNode.left;
}else{
parent.right = targetNode.left;
}
}else{
root = targetNode.left;
}
}else{
if(parent != null){
if(parent.left.value == value){
parent.left = targetNode.right;
}else{
parent.right = targetNode.right;
}
}else{
root = targetNode.right;
}
}
}
}
}
}
```

# 2, Balanced binary tree

## 1. Introduction

The binary sort tree can improve the search efficiency to some extent, but when the original sequence is ordered, such as sequence A = {1, 3, 5, 7, 9}. The binary sort tree constructed according to this sequence is a right oblique tree. At the same time, the binary tree degenerates into a single linked list, and the search efficiency is reduced to O(n)

The search efficiency of binary sort tree depends on the height of the tree, so keeping the height of the tree to the minimum can ensure the search efficiency of the tree. When the number of nodes is fixed, the balance between the left and right ends of the tree is maintained, and the search efficiency of the tree is the highest, so there is a balanced binary tree

## 2. Introduction

Balanced Binary Tree, also known as AVL tree, was proposed by the mathematicians adelse velskil and Landis of the former Soviet Union in 1962. It is an empty tree or the absolute value of the height difference between its left and right subtrees is no more than 1, and both the left and right subtrees are a Balanced Binary Tree

Equilibrium factor

The height (depth) difference between the left subtree and the right subtree of a node is the Balance Factor of the node. There is no node with a Balance Factor greater than 1 in the balanced binary tree. In a balanced binary tree, the balance factors of nodes can only take 0, 1 and - 1, respectively corresponding to the equal height of left and right subtrees, the higher the left subtree and the higher the right subtree

Minimum unbalanced subtree

The subtree with the root of the node whose absolute value of the first balance factor exceeds 1 is called the minimum unbalanced subtree. In other words, an unbalanced tree may have multiple subtrees unbalanced at the same time. At this time, as long as we adjust the smallest unbalanced subtree, we can adjust the unbalanced tree to a balanced tree

The imbalance adjustment of balanced binary tree is mainly realized by rotating the minimum imbalance subtree. There are two processing methods according to the direction of rotation: left rotation and right rotation

Sinistral

Idea:

1. Replace the current node with the right child node of the current node
2. The left subtree of the right child node becomes the right subtree of the current node
3. The current node becomes the left subtree of the right child node
```private void leftRotate(){
Node newNode = new Node(value);
newNode.left = left;
newNode.right = rightn.left;
value = right.value;
right = right.right;
left = newNode;
}
```

The following three figures are the actual left-handed process, which is helpful to understand the code

Dextral

Idea:

1. Replace the current node with the left child node of the current node
2. The right subtree of the left child node becomes the left subtree of the current node
3. The current node becomes the right subtree of the left sub node
```private void rightRotate(){
Node newNode = new Node(value);
newNode.right = right;
newNode.left = left.right;
value = left.value;
left = left.left;
right = newNode;
}
```

The following three figures are the actual right-handed process, which is helpful to understand the code

## 3. Insert node

There are four situations in which a balanced binary tree inserts nodes

Insertion modedescribeRotation mode
LLInserting nodes into the left subtree of the root node of the left subtree of A destroys the balanceRight rotation
RRInserting A node into the right subtree of the root node of the right subtree of A destroys the balanceLeft rotation
LRInserting A node into the right subtree of the root node of the left subtree of A destroys the balanceFirst left and then right
RLInserting A node into the left subtree of the root node of the right subtree of A destroys the balanceFirst right and then left

LL and RR have been mentioned in the above introduction. We focus on LR and RL

Both LR and RL cannot be rebalanced through one selection, as shown in the figure below

The left subtree of A is higher than the right subtree. If only one right rotation is performed, the change is:

We find that the right subtree of B is higher than the left subtree again

In order to rebalance the balanced binary tree whose insertion mode is LR or RL, we need to take the following two methods

For LR, turn left and then right

1. Rotate the left child node of the root node
2. Rotate the root node right

For RL. First right and then left

1. Rotate the right child node of the root node
2. Rotate the root node to the left

## 4. Delete node

The deletion operations of balanced binary tree and binary sort tree are the same, which are divided into four cases. However, after deleting nodes, the balanced binary tree needs to check the balance again and correct it

The difference between the delete operation and the balance correction after the insert operation is that after the insert operation, only the first non-equilibrium point popped up in the insert stack needs to be corrected, while the delete operation needs to correct all non-equilibrium points in the stack

For the correction of unbalanced state caused by deletion, it can be understood as follows: the deletion of left subtree or right subtree is equivalent to the insertion of right subtree or left subtree, and then select the corresponding rotation according to the four cases of upper insertion

## 5. Code implementation

```package com.sisyphus.BinaryTree.AVLTree;

public class AVLTreeDemo {
public static void main(String[] args){
int[] arr = {10,11,7,6,8,9};
AVLTree avlTree = new AVLTree();

for(int i = 0; i < arr.length; i++){
}

System.out.println("Medium order traversal");
avlTree.infixOrder();

System.out.println("Before deleting a node:");
System.out.println("Tree height:"+ avlTree.getRoot().height());
System.out.println("Left subtree height of tree:" + avlTree.getRoot().leftHeight());
System.out.println("Height of right subtree of tree:" + avlTree.getRoot().rightHeight());
System.out.println("The current root node is:" + avlTree.getRoot());

//        //Test delete a node
//        avlTree.delNode(7);
//        System.out.println("middle order traversal after deleting nodes");
//        avlTree.infixOrder();
//
//        //Test delete the second node
//        avlTree.delNode(10);
//        System.out.println("middle order traversal after deleting nodes:");
//        avlTree.infixOrder();

//After deleting two nodes, the test will show an imbalance, and then the balance tree will be adjusted automatically
avlTree.delNode(6);
avlTree.delNode(7);
System.out.println("Middle order traversal after deleting nodes");
avlTree.infixOrder();
System.out.println("Tree height:" + avlTree.getRoot().height());
System.out.println("Left subtree height of tree:" + avlTree.getRoot().leftHeight());
System.out.println("Height of right subtree of tree:" + avlTree.getRoot().rightHeight());
System.out.println("The current root node is:" + avlTree.getRoot());
System.out.println("The left child node of the current root node is:" + avlTree.getRoot().left);
System.out.println("The right child node of the current root node is:" + avlTree.getRoot().right);
System.out.println("The left child node and the right child node of the current root node are:" + avlTree.getRoot().left.right);
}
}

class Node{
int value;
Node left;
Node right;

public Node(int value){
this.value = value;
}

@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}

public Node search(int value){
if(value ==this.value){
return this;
}else if(value < this.value){
if(this.left == null){
return null;
}
return this.left.search(value);
}else{
if(this.right == null){
return null;
}
return this.right.search(value);
}
}

public Node searchParent(int value){
if((this.left != null && this.left.value == value) || (this.right != null && this.right.value == value)){
return this;
}else{
if(value < this.value && this.left != null){
return this.left.searchParent(value);
}else if(value > this.value && this.right != null){
return this.right.searchParent(value);
}else{
return null;
}
}
}

//Medium order traversal
public void infixOrder(){
if(this.left != null){
this.left.infixOrder();
}
System.out.println(this);
if (this.right != null){
this.right.infixOrder();
}
}

//Returns the height of the tree with the current node as the root node
public int height(){
return Math.max(left == null ? 0: left.height(), right == null ? 0 : right.height()) + 1;
}

//Returns the height of the left subtree
public int leftHeight(){
if(left == null){
return 0;
}
return left.height();
}

//Returns the height of the right subtree
public int rightHeight(){
if(right == null){
return 0;
}
return right.height();
}

//Left rotation
public void leftRotate(){
//Create a new node with the value of the root node of the current subtree
Node newNode = new Node(value);
//Set the left subtree of the new node as the left subtree of the current node
newNode.left = left;
//Set the right sub node of the new node as the left sub tree of the right sub node of the current node
newNode.right = right.left;
//Replace the value of the root node of the current subtree with the value of the right child node
value = right.value;
//Set the right subtree of the current node as the right subtree of the right child node
right = right.right;
//Replace the left child node of the current node with a new node
left = newNode;
}

//Right rotation
public void rightRotate(){
Node newNode = new Node(value);
newNode.right = right;
newNode.left = left.right;
value = left.value;
left = left.left;
right = newNode;
}

if(node == null){
return;
}

if(node.value < this.value){
if(this.left == null){
this.left = node;
}else{
}
}else{
if(this.right == null){
this.right = node;
}else{
}
}

//Different from the binary sort tree, the height difference between the left and right subtrees needs to be judged after adding nodes, and adjusted according to the situation

//If (right subtree height - left subtree height) > 1, rotate left
if(rightHeight() - leftHeight() > 1){
//If the left subtree height of the right subtree of the current node is greater than its right subtree height, adjust its right subtree first, that is, rotate it right
if(right != null && right.leftHeight() > right.rightHeight()){
//First, rotate the right child node of the current node
right.rightRotate();
//Then rotate the current node to the left
leftRotate();
}else{
leftRotate();
return;
}
}
//If (left subtree height - right subtree height) > 1, rotate right
if(leftHeight() - rightHeight() > 1){
//If the right subtree height of the left subtree of the current node is greater than its left subtree height, first adjust its left subtree, that is, rotate left
if(left != null && left.rightHeight() > left.leftHeight()){
//First, rotate the left child node of the current node
left.leftRotate();
//Then right rotate the current node
rightRotate();
}else{
rightRotate();
}
}
}
}

class AVLTree{
private Node root;

public Node getRoot(){
return root;
}

public void setRoot(Node root){
this.root = root;
}

public Node search(int value){
if(root == null){
return null;
}else{
return root.search(value);
}
}

public Node searchParent(int value){
if(root == null){
return null;
}else{
return root.searchParent(value);
}
}

public int delReturnMin(Node node){
while(node.left != null){
node = node.left;
}
delNode(node.value);
return node.value;
}

if(root == null){
root = node;
}else{
}
}

//Medium order traversal
public void infixOrder(){
if(root == null){
System.out.println("The tree is empty and cannot be traversed");
}else{
root.infixOrder();
}
}

//Delete Vertex
public void delNode(int value){
if(root == null){
return;
}else{
Node targetNode = root.search(value);

if(targetNode == null){
return;
}

Node parent = searchParent(value);

//Delete leaf node
if(targetNode.left == null && targetNode.right == null){
if(parent.left != null && parent.left.value == value){
parent.left = null;
}else{
parent.right = null;
}
}
//Delete a node with two child nodes
else if(targetNode.left != null && targetNode.right != null){
int minVal = delReturnMin(targetNode.right);
targetNode.value = minVal;
}
//Delete a node with only one child node
else{
if(targetNode.left != null){
if(parent != null){
if(parent.left.value == value){
parent.left = targetNode.left;
}else{
parent.right = targetNode.left;
}
}else{
root = targetNode.left;
}
}else{
if(parent != null){
if(parent.left.value == value){
parent.left = targetNode.right;
}else{
parent.right = targetNode.right;
}
}else{
root = targetNode.right;
}
}
}
}

//Different from the binary sort tree, the height difference between the left and right subtrees needs to be judged and adjusted according to the situation after deleting the node

//If (right subtree height - left subtree height) > 1, rotate left
if(root.rightHeight() - root.leftHeight() > 1){
//If the height of the left subtree of the right subtree of the current node is greater than its right subtree, first adjust its right subtree, that is, rotate it right
if(root.right != null && root.right.leftHeight() > root.right.rightHeight()){
//First, rotate the right child node of the current node
root.right.rightRotate();
//Then rotate the current node to the left
root.leftRotate();
}else{
root.leftRotate();
return;
}
}

//If (left subtree height - right subtree height) > 1, rotate right
if(root.leftHeight() - root.rightHeight() > 1){
//If the right subtree height of the left subtree of the current node is greater than its left subtree height, first adjust its left subtree, that is, rotate left
if(root.left != null && root.left.rightHeight() > root.left.leftHeight()){
//First, rotate the left child node of the current node
root.left.leftRotate();
//Then right rotate the current node
root.rightRotate();
}else{
root.rightRotate();
}
}
}
}
```

Posted by doublebassdanny on Mon, 11 Oct 2021 17:31:27 -0700