# Balanced binary tree (AVL) (Java implementation)

## Balanced binary tree (AVL) (Java implementation)

#### 1. Problems in binary search tree

Although binary tree search has some advantages in query, deletion and addition, its efficiency is also very low in some cases. For example, the following binary search tree: We find that its right subtree is very high, which makes it lose the function of efficient search that binary tree originally has. Its search efficiency is even lower than that of linked list, because it needs to judge whether it has left subtree or right subtree when traversing a node. In order to avoid this situation, a balanced binary tree is introduced.

#### 2. Definition of balanced binary tree (AVL)

First, the balanced binary tree is a special binary search tree. Secondly, the absolute values of height of left and right subtrees of balanced binary trees are less than 1

#### 3. Find the height of binary tree

Recursion, it's not easy to understand the code directly. It's easy to understand when drawing.

```/**
* Height of binary tree
* @return
*/
public int height(){
return Math.max(left==null?0:left.height(),right==null?0:right.height())+1;
}
```

Understand the above code, similarly, the height of the left and right subtrees is also very good.

```/**
* Height of left subtree
* @return
*/
public int leftHeight(){
if (left==null){
return 0;
}
return left.height();
}

/**
* Height of right subtree
* @return
*/
public int rightHeight(){
if (right==null){
return 0;
}
return right.height();
}
```

Let's test the height of the binary tree, the height of the left subtree and the height of the right subtree ```public class AVLTreeDemo {
public static void main(String[] args) {
int[] arr={4,3,6,5,7,8};
//Create an AVLTree object
AVLTree avlTree = new AVLTree();
for (int i = 0; i < arr.length; i++) {
}
System.out.println("Sequential traversal");
avlTree.infixOrder();
System.out.println("Before balancing");
System.out.println("Height of tree:"+avlTree.getRoot().height());
System.out.println("Height of left subtree:"+avlTree.getRoot().leftHeight());
System.out.println("Height of right subtree:"+avlTree.getRoot().rightHeight());
}
}
```

The output is as follows, exactly the same as the picture we see: #### 4. The left rotation of BST forms AVL

Conditions for left rotation: when a node is added, the height of the right subtree - the height of the left subtree > 1, the left rotation occurs.

```/**
* Left rotation method
*/
public void leftRotate(){
//Create a new node with the value of the current root node
Node newNode = new Node(this.value);
//Set the new node's left subtree to the current node's left subtree
newNode.left=this.left;
//Set the right subtree of the new node to the left subtree of the right subtree of the current node
newNode.right=this.right.left;
//Replace the value of the current node with the value of the right child node
this.value=this.right.value;
//Set the right subtree of the current node to the right subtree of the right subtree of the current node
this.right=this.right.right;
//Set the left child of the current node as a new node
this.left=newNode;
}
if (node==null){
return;
}
//Determine the relationship between the value of the incoming node and the value of the node of the current subtree
if (node.value<this.value){
//If the left child of the current node is empty
if (this.left==null){
this.left=node;
}else {
}
}else {//The value of the added node is greater than the value of the current node
if (this.right==null){
this.right=node;
}else {//Recursively add to right subtree
}
}
//When a node is added, the height of the right subtree - the height of the left subtree is more than 1, and the left rotation occurs
if (rightHeight()-leftHeight()>1){
leftRotate();//Left rotation
}
}
```

Continuing to test the height of a binary tree, we find that BTS has self balanced into AVL. After left rotation, the original binary tree becomes like this:  #### 5. Right rotation of BST to form AVL

Conditions for right rotation: when a node is added, the height of the left subtree - the height of the right subtree is more than 1, and right rotation occurs. ```/**
* Right rotation method
*/
public void rightRotate(){
//Create a new node with the value of the current root node
Node newNode = new Node(this.value);
//Set the right subtree of the new node as the right subtree of the current node
newNode.right=this.right;
//Set the left subtree of the new node as the right subtree of the left subtree of the current node
newNode.left=this.left.right;
//Replace the value of the current node with the value of the left child node
this.value=this.left.value;
//Set the left subtree of the current node to the left subtree of the left subtree of the current node
this.left=this.left.left;
//Set the right child of the current node as a new node
this.right=newNode;
}
if (node==null){
return;
}
//Determine the relationship between the value of the incoming node and the value of the node of the current subtree
if (node.value<this.value){
//If the left child of the current node is empty
if (this.left==null){
this.left=node;
}else {
}
}else {//The value of the added node is greater than the value of the current node
if (this.right==null){
this.right=node;
}else {//Recursively add to right subtree
}
}
//When a node is added, the height of the right subtree - the height of the left subtree is more than 1, and the left rotation occurs
if (rightHeight()-leftHeight()>1){
/* if (this.right!=null&&this.right.rightHeight()<this.right.leftHeight()){
//Rotate the right subtree first

}*/
leftRotate();//Left rotation
}
//When a node is added, the height of the left subtree - the height of the right subtree is more than 1, and the right rotation occurs
if (leftHeight()-rightHeight()>1){
rightRotate();//Right choice
}
}
```

Test one:

```public class AVLTreeDemo {
public static void main(String[] args) {
//int[] arr={4,3,6,5,7,8};
int[] arr={10,12,8,9,7,6};
//Create an AVLTree object
AVLTree avlTree = new AVLTree();
for (int i = 0; i < arr.length; i++) {
}
System.out.println("Sequential traversal");
avlTree.infixOrder();
//System.out.println("before no balance processing");
System.out.println("After balancing");
System.out.println("Height of tree:"+avlTree.getRoot().height());
System.out.println("Height of left subtree:"+avlTree.getRoot().leftHeight());
System.out.println("Height of right subtree:"+avlTree.getRoot().rightHeight());
}
}
```

The running results are as follows. It is indeed balanced. Let's take a look at the right rotated binary tree: #### 6. double rotation

```//When a node is added, the height of the right subtree - the height of the left subtree is more than 1, and the left rotation occurs
if (rightHeight()-leftHeight()>1){
//If the height of the left subtree of the right subtree of the current node is greater than the height of the right subtree of its right subtree
if (this.right!=null&&this.right.rightHeight()<this.right.leftHeight()){
//First rotate the right subtree to the right
this.right.rightRotate();
//Rotate left on current node
this.leftRotate();
}else {
this.leftRotate();//Left rotation
}
return;//You must return
}
//When a node is added, the height of the left subtree - the height of the right subtree is more than 1, and the right rotation occurs
if (leftHeight()-rightHeight()>1){
//If the height of the right subtree of its left subtree is greater than that of its left subtree
if (this.left!=null&&this.left.rightHeight()>this.left.leftHeight()){
//First rotate the left subtree of the current node to the left
this.left.leftRotate();
//Rotate the current node to the right
this.rightRotate();
}else {
//Just rotate right
this.rightRotate();
}
return;
}
```

#### 7. summary

All the code is here. The most important idea is to master how to rotate. In fact, if you have made every step clear, the code is very simple to implement.

```package Day42;

/**
* @Author Zhongger
* @Description Balanced binary tree-+-
* @Date 2020.3.14
*/
public class AVLTreeDemo {
public static void main(String[] args) {
//int[] arr={4,3,6,5,7,8}; left
//int[] arr={10,12,8,9,7,6}; right
int[] arr={10,11,7,6,8,9};//Double rotation
//Create an AVLTree object
AVLTree avlTree = new AVLTree();
for (int i = 0; i < arr.length; i++) {
}
System.out.println("Sequential traversal");
avlTree.infixOrder();
//System.out.println("before no balance processing");
System.out.println("After balancing");
System.out.println("Height of tree:"+avlTree.getRoot().height());
System.out.println("Height of left subtree:"+avlTree.getRoot().leftHeight());
System.out.println("Height of right subtree:"+avlTree.getRoot().rightHeight());
}
}
class AVLTree{
private Node root;

public Node getRoot() {
return root;
}

/**
* Returns the smallest node of the binary sort tree with node as the root node, and deletes the smallest node
* @param node
* @return
*/
public int deleteRightTreeMin(Node node){
Node target=node;
//Loop through the left node to find the minimum
while (target.left!=null){
target=target.left;
}
//This is target, which points to the smallest node
deleteNode(target.value);//Deleted
return target.value;
}

//Find nodes to delete
public Node search(int value){
if (root==null){
return null;
}else {
return root.search(value);
}
}
//Find the parent of the node to delete
public Node searchParent(int value){
if (root==null){
return null;
}else {
return root.searchParent(value);
}
}

public void deleteNode(int value){
if (root==null){
return;
}else {
Node targetNode = search(value);
if (targetNode==null){//No nodes found to delete
return;
}
//If the targetNode does not have a parent
if (root.left==null&&root.right==null){
root=null;
}
//Parent of targetNode encountered
Node parentNode = searchParent(value);
//If the node to be deleted is a leaf node
if (targetNode.left==null&&targetNode.right==null){
//Determine whether the targetNode is the left or right child of the parent node
if ((parentNode.left!=null)&&(parentNode.left.value==value)){
parentNode.left=null;
}else if ((parentNode.right!=null)&&(parentNode.right.value==value)){
parentNode.right=null;
}
}else if (targetNode.left!=null&&targetNode.right!=null){//Delete a node with two subtrees
int minVal = deleteRightTreeMin(targetNode.right);
targetNode.value=minVal;
}else {//Delete a node with only one subtree
if (targetNode.left!=null){//Left child tree
if (parentNode!=null){
//If targetNode is the left child of parentNode
if (parentNode.left.value==value){
parentNode.left=targetNode.left;
}else {//targetNode is the right child of parentNode
parentNode.right=targetNode.left;
}
}else {
root=targetNode.left;
}

}else {//Right subtree
if (parentNode!=null){
if (parentNode.left.value==value){
parentNode.left=targetNode.right;
}else {
parentNode.right=targetNode.right;
}
}else {
root=targetNode.right;
}

}
}
}
}

if (root==null){
root=node;//If root is empty, direct root to node
}else {
}
}

//Sequential traversal
public void infixOrder(){
if (root!=null){
root.infixOrder();
}
else {
System.out.println("Binary sort tree is empty, unable to traverse");
}
}
}

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

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

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

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

/**
* Right rotation method
*/
public void rightRotate(){
//Create a new node with the value of the current root node
Node newNode = new Node(this.value);
//Set the right subtree of the new node as the right subtree of the current node
newNode.right=this.right;
//Set the left subtree of the new node as the right subtree of the left subtree of the current node
newNode.left=this.left.right;
//Replace the value of the current node with the value of the left child node
this.value=this.left.value;
//Set the left subtree of the current node to the left subtree of the left subtree of the current node
this.left=this.left.left;
//Set the right child of the current node as a new node
this.right=newNode;
}

/**
* Height of left subtree
* @return
*/
public int leftHeight(){
if (left==null){
return 0;
}
return left.height();
}

/**
* Height of right subtree
* @return
*/
public int rightHeight(){
if (right==null){
return 0;
}
return right.height();
}

/**
* Height of left and right subtrees of binary trees
* @return
*/
public int height(){
return Math.max(left==null?0:left.height(),right==null?0:right.height())+1;
}

/**
* Find nodes to delete
* @param value The value of the node to delete
* @return Return the node if found, otherwise return null
*/
public Node search(int value){
if (this.value==value){//This node is found
return this;
}else if (value<this.value){//If the value to be found is less than the current node, recursively find the left subtree
//If the left child node is empty
if (this.left==null){
return null;
}
return this.left.search(value);
}else {
//If the right child node is empty
if (this.right==null){
return null;
}
return this.right.search(value);
}
}

/**
* Find the parent of the node to delete
* @param value The value of the node to delete
* @return Return the node if found, otherwise return null
*/
public Node searchParent(int value){
//If the current node is the parent of the node to be deleted, return
if ((this.left!=null&&this.left.value==value)||
(this.right!=null&&this.right.value==value)){
return this;
}else {
//If the value to be found is less than the value of the current node, and the left node of the current node is not empty
if (value<this.value&&this.left!=null){
return this.left.searchParent(value);//Left subtree recursive search
}else if (value>=this.value&&this.right!=null){
return this.right.searchParent(value);//Recursive search of right subtree
}else {
return null;
}
}
}

if (node==null){
return;
}
//Determine the relationship between the value of the incoming node and the value of the node of the current subtree
if (node.value<this.value){
//If the left child of the current node is empty
if (this.left==null){
this.left=node;
}else {
}
}else {//The value of the added node is greater than the value of the current node
if (this.right==null){
this.right=node;
}else {//Recursively add to right subtree
}
}
//When a node is added, the height of the right subtree - the height of the left subtree is more than 1, and the left rotation occurs
if (rightHeight()-leftHeight()>1){
//If the height of the left subtree of the right subtree of the current node is greater than the height of the right subtree of its right subtree
if (this.right!=null&&this.right.rightHeight()<this.right.leftHeight()){
//First rotate the right subtree to the right
this.right.rightRotate();
//Rotate left on current node
this.leftRotate();
}else {
this.leftRotate();//Left rotation
}
return;//You must return
}
//When a node is added, the height of the left subtree - the height of the right subtree is more than 1, and the right rotation occurs
if (leftHeight()-rightHeight()>1){
//If the height of the right subtree of its left subtree is greater than that of its left subtree
if (this.left!=null&&this.left.rightHeight()>this.left.leftHeight()){
//First rotate the left subtree of the current node to the left
this.left.leftRotate();
//Rotate the current node to the right
this.rightRotate();
}else {
//Just rotate right
this.rightRotate();
}
return;
}
}

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

```  44 original articles published, 91 praised, 20000 visitors+

Tags: less Java

Posted on Sat, 14 Mar 2020 02:20:36 -0400 by fredi_bieging