DEV Community

Lalit Yadav
Lalit Yadav

Posted on

3

AVL Tree C++

AVL Tree is a balanced binary search tree in which any two subtree height only differ by at most 1 i.e height of |Left child - Right child| <= 1. Along with key and value at each node we also store the computed Height property.

We do Rebalancing if the difference is more than 1.
AVL supports following operations:-

  • Find in O(logN)
  • Insert in O(logN)
  • Delete in O(logN)

Analysis of operations

 AVLInsert(k, R)
  Insert(k, R)
  N <- Find(k, R)
  Rebalance(N)

 Rebalancing
 if |N.Left.Height - N.Right.Height| <= 1

 Rebalance(N)
  p <- N.Parent
  if N.Left.Height > N.Right.Height + 1:
    RebalanceRight(N)
  if N.Right.Height > N.Left.Height + 1:
    RebalanceLeft(N)
  AdjustHeight(N)
  if P != null:
    Rebalance(N)

 AdjustHeight(N)
  N.Height <- 1 + max(N.Left.Height + N.Right.Height)
Enter fullscreen mode Exit fullscreen mode

Code

The code is pretty straightforward, we will just implement the operations. It is self explanatory and pretty verbose


//
//  AVLTree.h
//  Data structures
//
//  Created by Lalit Yadav on 06/09/20.
//  Copyright © 2020 Lalit Yadav. All rights reserved.
//

#ifndef AVLTree_h
#define AVLTree_h

#include <iostream>

using namespace std;

struct Node {
  int data;
  int height;
  Node * parent;
  Node * left;
  Node * right;
};

typedef Node * Nodeptr;

class AVLTree {
  Nodeptr root;
  Nodeptr Maximum(Nodeptr node);
  int GetHeight(Nodeptr node);
  void AdjustHeight(Nodeptr node);
  void ReplaceChild(Nodeptr parent, Nodeptr child, Nodeptr new_child);

  void RotateLeft(Nodeptr node);
  void RotateRight(Nodeptr node);

  void Rebalance(Nodeptr node);
  void RebalanceLeft(Nodeptr node);
  void RebalanceRight(Nodeptr node);
  public:
    AVLTree(): root(nullptr) {}
  AVLTree(int key);
  bool IsEmpty();
  Nodeptr Root();
  Nodeptr Find(int key);
  void Insert(int key);
  void Delete(int key);
  void PrintInOrder(Nodeptr node);
  void PrintPreOrder(Nodeptr node);
};

bool AVLTree::IsEmpty() {
  return root == nullptr;
}

Nodeptr AVLTree::Root() {
  return root;
}

Nodeptr AVLTree::Maximum(Nodeptr node) {
  if (node -> right != NULL) {
    return Maximum(node -> right);
  } else {
    return node;
  }
}

int AVLTree::GetHeight(Nodeptr node) {
  if (node == nullptr)
    return 0;

  return node -> height;
}

Nodeptr AVLTree::Find(int key) {
  if (IsEmpty()) {
    return nullptr;
  }

  auto parent = root;

  while (parent != nullptr) {
    if (key > parent -> data && parent -> right != nullptr)
      parent = parent -> right;
    else if (key < parent -> data && parent -> left != nullptr)
      parent = parent -> left;
    else
      return parent;
  }

  return parent;
}

void AVLTree::AdjustHeight(Nodeptr node) {
  node -> height = 1 + max(GetHeight(node -> left), GetHeight(node -> right));
}

void AVLTree::RotateLeft(Nodeptr node) {
  auto pivot = node -> right;

  // Update the parent of the node
  pivot -> parent = node -> parent;
  node -> parent = pivot;

  // Update the child of of the updated parent
  if (pivot -> parent == nullptr)
    root = pivot;
  else if (pivot -> parent -> left == node)
    pivot -> parent -> left = pivot; // Update the child link of the parent
  else
    pivot -> parent -> right = pivot;

  node -> right = pivot -> left;

  if (pivot -> left != nullptr)
    pivot -> left -> parent = node;

  pivot -> left = node;

  AdjustHeight(node);
  AdjustHeight(pivot);
}

void AVLTree::RotateRight(Nodeptr node) {
  auto pivot = node -> left;

  pivot -> parent = node -> parent;
  node -> parent = pivot;

  if (pivot -> parent == nullptr)
    root = pivot;
  else if (pivot -> parent -> left == node)
    pivot -> parent -> left = pivot;
  else
    pivot -> parent -> right = pivot;

  node -> left = pivot -> right;

  if (pivot -> right != nullptr)
    pivot -> right -> parent = node;

  pivot -> right = node;

  AdjustHeight(node);
  AdjustHeight(pivot);
}

void AVLTree::RebalanceLeft(Nodeptr node) {
  auto right_child = node -> right;

  if (right_child != nullptr) {
    if (GetHeight(right_child -> left) > GetHeight(right_child -> right))
      RotateRight(right_child);
  }

  RotateLeft(node);
}

void AVLTree::RebalanceRight(Nodeptr node) {
  auto left_child = node -> left;

  if (left_child != nullptr) {
    if (GetHeight(left_child -> right) > GetHeight(left_child -> left))
      RotateLeft(left_child);
  }

  RotateRight(node);
}

void AVLTree::Rebalance(Nodeptr node) {
  auto parent = node -> parent;

  if (GetHeight(node -> left) > GetHeight(node -> right) + 1)
    RebalanceRight(node);

  if (GetHeight(node -> right) > GetHeight(node -> left) + 1)
    RebalanceLeft(node);

  AdjustHeight(node);

  if (parent != nullptr) {
    Rebalance(parent);
  }
}

void AVLTree::Insert(int key) {
  auto p = new Node;

  p -> data = key;
  p -> height = 0;
  p -> parent = nullptr;
  p -> left = nullptr;
  p -> right = nullptr;

  if (IsEmpty()) {
    root = p;
  } else {
    auto parent = Find(key);
    p -> height = 1;

    if (key < parent -> data)
      parent -> left = p;
    else
      parent -> right = p;

    p -> parent = parent;
    Rebalance(parent);
  }
}

void AVLTree::Delete(int key) {
  auto node = Find(key);

  if (node == nullptr)
    return;

  if (node -> right == nullptr && node -> left == nullptr) {
    if (node -> parent == nullptr) {
      root = nullptr;
    } else {
      ReplaceChild(node -> parent, node, nullptr);
      Rebalance(node -> parent);
    }
  } else if (node -> left == nullptr) {
    // Replace the node with it's right child
    if (node -> parent == nullptr) {
      root = node -> right;
      node -> right -> parent = nullptr;
      Rebalance(node -> right);
    } else {
      ReplaceChild(node -> parent, node, node -> right);
      node -> right -> parent = node -> parent;
      Rebalance(node -> parent);
    }
  } else {
    // Replace the node with the maximum key from it's left child
    auto new_node = Maximum(node -> left);

    if (node -> parent == nullptr) {
      root = new_node;

      new_node -> right = node -> right;
      new_node -> left = node -> left;

      Rebalance(new_node);
    } else {
      auto parent_new_node = new_node -> parent;
      ReplaceChild(node -> parent, node, new_node);
      ReplaceChild(new_node -> parent, new_node, nullptr);

      new_node -> parent = node -> parent;
      new_node -> left = node -> left;

      if (node -> right != nullptr) {
        new_node -> right = node -> right;
        new_node -> right -> parent = new_node;
      }

      if (parent_new_node -> parent == node) {
        parent_new_node -> parent = new_node;
      }

      Rebalance(parent_new_node);
    }
  }

  delete node;
}

void AVLTree::ReplaceChild(Nodeptr parent, Nodeptr child, Nodeptr new_child) {
  if (parent -> left == child) {
    parent -> left = new_child;
  } else {
    parent -> right = new_child;
  }
}

void AVLTree::PrintInOrder(Nodeptr node) {
  if (node == nullptr)
    return;

  PrintInOrder(node -> left);
  cout << node -> data << ' ';
  PrintInOrder(node -> right);
}

void AVLTree::PrintPreOrder(Nodeptr node) {
  if (node == nullptr)
    return;

  cout << node -> data << ' ';
  PrintPreOrder(node -> left);
  PrintPreOrder(node -> right);
}

#endif /* AVLTree_h */
Enter fullscreen mode Exit fullscreen mode

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay