From a1fcc5d51abac0a6b9c0eeed411b0c9d19d49889 Mon Sep 17 00:00:00 2001
From: Abhishek Prakash <abhishekabby@gmail.com>
Date: Fri, 24 Nov 2017 15:43:13 +0530
Subject: [PATCH 1/6] Added AVL tree

---
 src/binary-search-tree/avl-tree.js           | 78 ++++++++++++++++++++
 src/binary-search-tree/avl-tree.spec.js      | 34 +++++++++
 src/binary-search-tree/binary-search-tree.ts | 11 ++-
 3 files changed, 117 insertions(+), 6 deletions(-)
 create mode 100644 src/binary-search-tree/avl-tree.js
 create mode 100644 src/binary-search-tree/avl-tree.spec.js

diff --git a/src/binary-search-tree/avl-tree.js b/src/binary-search-tree/avl-tree.js
new file mode 100644
index 0000000..1061881
--- /dev/null
+++ b/src/binary-search-tree/avl-tree.js
@@ -0,0 +1,78 @@
+import { BST, BSTNode } from './binary-search-tree';
+
+export class AVLNode extends BSTNode {
+  constructor(key, details = null, left = null, right = null, height = 0) {
+    super(key, details, left, right);
+    this._height = height;
+  }
+
+  get height() { return this._height; }
+  set height(h) { this._height = h; }
+}
+
+export const ROTATION = {
+  LEFT_LEFT: 'll',
+  LEFT_RIGHT: 'lr',
+  RIGHT_RIGHT: 'rr',
+  RIGHT_LEFT: 'rl'
+};
+
+export class AVLTree extends BST {
+  insert(el, root = this.root) {
+
+    if (this.root === null) {
+      const node = new AVLNode(el);
+      this.root = node;
+      this.len = ++this.len;
+      return;
+    }
+
+    if (root === null) {
+      this.len = ++this.len;
+      return new AVLNode(el);
+    }
+
+    if (el < root.key) {
+      root.left = this.insert(el, root.left);
+    } else if (el > root.key) {
+      root.right = this.insert(el, root.right);
+    } else {
+      return root;
+    }
+
+    root.height = this.height(root);
+    const balanceFactor = this.getBalanceState(root);
+
+    if (balanceFactor > 1 || balanceFactor < -1) {
+      this.rebalance(node);
+    }
+  }
+
+  rebalance(node) {
+    if (node.left.height - node.right.height > 1) {
+      if (this.height(node.left.left) > this.height(node.left.right)) {
+        this.rightRotate(node);
+      } else {
+        this.leftRightRotate(node);
+      }
+    } else {
+      if (this.height(node.right.left) > this.height(node.right.right)) {
+        this.leftRotate(node);
+      } else {
+        this.rightLeftRotate(node);
+      }
+    }
+  }
+
+  leftRotate(node) { }
+  rightRotate(node) { }
+  leftRightRotate(node) { }
+  rightLeftRotate(node) { }
+
+  getBalanceState(node) {
+    const leftHeight = node.left ? node.left.height : 0;
+    const rightHeight = node.right ? node.right.height : 0;
+
+    return leftHeight - rightHeight;
+  }
+}
\ No newline at end of file
diff --git a/src/binary-search-tree/avl-tree.spec.js b/src/binary-search-tree/avl-tree.spec.js
new file mode 100644
index 0000000..75bf523
--- /dev/null
+++ b/src/binary-search-tree/avl-tree.spec.js
@@ -0,0 +1,34 @@
+import { AVLTree } from './avl-tree';
+
+describe('AVL Tree', () => {
+  let avlTree;
+  beforeEach(() => {
+    avlTree = new AVLTree;
+  });
+
+  it('should create an avl tree', () => {
+    expect(avlTree).toBeDefined();
+    expect(avlTree.len).toBe(0);
+    expect(avlTree.root).toBe(null);
+  });
+
+  it('should insert nodes in the tree', () => {
+    avlTree.insert(5);
+    expect(avlTree.len).toBe(1);
+    expect(avlTree.root.key).toBe(5);
+    expect(avlTree.root.height).toBe(0);
+
+    avlTree.insert(9);
+    expect(avlTree.len).toBe(2);
+    expect(avlTree.root.right.key).toBe(9);
+    expect(avlTree.root.right.height).toBe(0);
+    expect(avlTree.root.height).toBe(1);
+
+    avlTree.insert(9);
+    expect(avlTree.len).toBe(2);
+    expect(avlTree.root.right.key).toBe(9);
+    expect(avlTree.root.right.height).toBe(0);
+    expect(avlTree.root.height).toBe(1);
+  });
+});
+
diff --git a/src/binary-search-tree/binary-search-tree.ts b/src/binary-search-tree/binary-search-tree.ts
index d93e2f6..f26b4fe 100644
--- a/src/binary-search-tree/binary-search-tree.ts
+++ b/src/binary-search-tree/binary-search-tree.ts
@@ -67,10 +67,7 @@ const preOrderTraversal = Symbol("preorder");
 const postOrderTraversal = Symbol("postorder");
 const levelOrderTraversal = Symbol("levelorder");
 
-/**
- * Private properties name
- */
-const length = Symbol("length");
+
 
 /**
  * Binary Search Tree
@@ -83,8 +80,10 @@ export class BST<T> {
     this.root = null;
     this.length = 0;
   }
-
-  get len() {
+  set len(l) {
+    this.length = l;
+  }
+  get len(): number {
     return this.length;
   }
 

From a2eff3a473d60ccfa8ac6db474bc8076793ff4db Mon Sep 17 00:00:00 2001
From: Abhishek Prakash <abhishekabby@gmail.com>
Date: Sat, 23 Dec 2017 22:02:30 +0530
Subject: [PATCH 2/6] Updated detail

---
 README.md    | 3 +++
 package.json | 3 ++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 173c0ad..3af1689 100644
--- a/README.md
+++ b/README.md
@@ -50,6 +50,7 @@ Trigger production build
 Data structures covered so far -
 
 - [Binary Search Tree](#binary-search-tree)
+- [AVL Tree](#avl-tree) - In Progress
 - [Graph](#graph)
 - [Queue](#queue)
 - [Linked List](#link-list)
@@ -130,6 +131,8 @@ Delete elements from binary search tree
 bst.delete(10);
 bst.delete(20);
 ```
+# <a name="avl-tree"></a>AVL Tree
+AVL Tree Docs.
 
 # <a name="graph"></a> Graph
 
diff --git a/package.json b/package.json
index 437d2f0..d79e3f5 100644
--- a/package.json
+++ b/package.json
@@ -44,7 +44,8 @@
     "es6",
     "queue",
     "graph",
-    "binary search tree"
+    "binary search tree",
+    "avl tree"
   ],
   "author": {
     "name": "Abhishek Prakash",

From 873d2ff84ecaf9e4c52eff418d892bbac2855dcc Mon Sep 17 00:00:00 2001
From: Abhishek Prakash <abhishekabby@gmail.com>
Date: Tue, 11 Aug 2020 16:39:13 +0200
Subject: [PATCH 3/6] added avlnode and unit test case

---
 package.json                           |  1 +
 src/avl-tree/__test__/avl-node.spec.ts | 59 ++++++++++++++++++++++++
 src/avl-tree/avl-node.ts               | 64 ++++++++++++++++++++++++++
 src/avl-tree/avl.ts                    | 21 +++++++++
 4 files changed, 145 insertions(+)
 create mode 100644 src/avl-tree/__test__/avl-node.spec.ts
 create mode 100644 src/avl-tree/avl-node.ts
 create mode 100644 src/avl-tree/avl.ts

diff --git a/package.json b/package.json
index d79e3f5..2eb053d 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
     "prepare": "npm run build & npm run dev",
     "publish:npm": "npm publish --access public",
     "test:jest": "jest",
+    "test:jest:watch": "jest --watch",
     "lint": "eslint src/ --ext .ts"
   },
   "jest": {
diff --git a/src/avl-tree/__test__/avl-node.spec.ts b/src/avl-tree/__test__/avl-node.spec.ts
new file mode 100644
index 0000000..e1bb12d
--- /dev/null
+++ b/src/avl-tree/__test__/avl-node.spec.ts
@@ -0,0 +1,59 @@
+import { AVLNode } from "../avl-node";
+
+class Int extends AVLNode<number> {
+  constructor(value: number) {
+    super(value)
+  }
+
+  public compareTo(o: AVLNode<number>): number {
+    if (this.getValue() < o.getValue()) {
+      return -1;
+    } else if (this.getValue() > o.getValue()) {
+      return 1;
+    } else {
+      return 0;
+    }
+  }
+}
+
+describe("Test for AVLNode", () => {
+  let node: AVLNode<number>;
+  let node1: AVLNode<number>;
+  let node2: AVLNode<number>;
+  let node3: AVLNode<number>;
+
+  beforeEach(() => {
+    node = new Int(5);
+    node1 = new Int(4);
+    node2 = new Int(5);
+    node3 = new Int(6);
+  });
+
+  it("should create an AVL node of type number", () => {
+    expect(node).toBeDefined();
+    expect(node.getValue()).toBe(5);
+    expect(node.getLeft()).toBe(null);
+    expect(node.getRight()).toBe(null);
+    expect(node.getLeftHeight()).toBe(0);
+    expect(node.getRightHeight()).toBe(0);
+    expect(node.nodeHeight()).toBe(0);
+    expect(node.balanceFactor()).toBe(0);
+    expect(node.compareTo(node1)).toBe(1);
+    expect(node.compareTo(node2)).toBe(0);
+    expect(node.compareTo(node3)).toBe(-1);
+  });
+
+  it("should calculate the hight correctly", () => {
+    node.setLeft(node1);
+    node.setRight(node3);
+    node.setLeftHeight(1);
+    node.setRightHeight(1)
+
+    expect(node.getLeft()).toEqual(node1);
+    expect(node.getRight()).toEqual(node3);
+    expect(node.getLeftHeight()).toBe(1);
+    expect(node.getRightHeight()).toBe(1);
+    expect(node.nodeHeight()).toBe(1);
+    expect(node.balanceFactor()).toBe(0);
+  })
+});
\ No newline at end of file
diff --git a/src/avl-tree/avl-node.ts b/src/avl-tree/avl-node.ts
new file mode 100644
index 0000000..e14079a
--- /dev/null
+++ b/src/avl-tree/avl-node.ts
@@ -0,0 +1,64 @@
+export abstract class AVLNode<T> {
+  private left: AVLNode<T>;
+  private right: AVLNode<T>;
+  private leftHeight: number;
+  private rightHeight: number;
+  private value: number;
+
+  constructor(value: number) {
+    this.left = null;
+    this.right = null;
+    this.leftHeight = 0;
+    this.rightHeight = 0;
+    this.value = value;
+  }
+
+  public balanceFactor(): number {
+    return (this.rightHeight - this.leftHeight);
+  }
+
+  public nodeHeight(): number {
+    return (this.rightHeight > this.leftHeight) ? this.rightHeight : this.leftHeight;
+  }
+
+  public abstract compareTo(o: AVLNode<number>): number
+
+  /* #region(collapsed) Getter and Setter */
+  public getLeft(): AVLNode<T> {
+    return this.left;
+  }
+
+  public setLeft(left: AVLNode<T>): void {
+    this.left = left;
+  }
+
+  public getRight(): AVLNode<T> {
+    return this.right;
+  }
+
+  public setRight(right: AVLNode<T>): void {
+    this.right = right;
+  }
+
+  public getLeftHeight(): number {
+    return this.leftHeight;
+  }
+
+  public setLeftHeight(leftHeight: number): void {
+    this.leftHeight = leftHeight;
+  }
+
+  public getRightHeight(): number {
+    return this.rightHeight;
+  }
+
+  public setRightHeight(rightHeight: number): void {
+    this.rightHeight = rightHeight;
+  }
+
+  public getValue(): number {
+    return this.value;
+  }
+  /* #endregion */
+
+}
\ No newline at end of file
diff --git a/src/avl-tree/avl.ts b/src/avl-tree/avl.ts
new file mode 100644
index 0000000..4e52642
--- /dev/null
+++ b/src/avl-tree/avl.ts
@@ -0,0 +1,21 @@
+import { AVLNode } from "./avl-node";
+
+export interface IAVLTree<T> {
+  insert(node: AVLNode<T>): boolean
+  search(node: AVLNode<T>): boolean
+  delete(node: AVLNode<T>): boolean
+}
+
+export class AVLTree<T> implements IAVLTree<T> {
+  constructor(private root: AVLNode<T> = null) { }
+
+  public insert(node: AVLNode<T>): boolean { }
+  public search(node: AVLNode<T>): boolean { }
+  public delete(node: AVLNode<T>): boolean { }
+
+  private detectRotation(node: AVLNode<T>): void { }
+  private leftRotation(node: AVLNode<T>): void { }
+  private rightRotation(node: AVLNode<T>): void { }
+  private leftRightRotation(node: AVLNode<T>): void { }
+  private rightLeftRotation(node: AVLNode<T>): void { }
+}
\ No newline at end of file

From 4c5afa352fc34add70bf045422df27a77a016430 Mon Sep 17 00:00:00 2001
From: Abhishek Prakash <abhishekabby@gmail.com>
Date: Wed, 12 Aug 2020 10:22:15 +0200
Subject: [PATCH 4/6] added TODOs

---
 src/avl-tree/avl.ts | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/avl-tree/avl.ts b/src/avl-tree/avl.ts
index 4e52642..fd22c2f 100644
--- a/src/avl-tree/avl.ts
+++ b/src/avl-tree/avl.ts
@@ -9,9 +9,18 @@ export interface IAVLTree<T> {
 export class AVLTree<T> implements IAVLTree<T> {
   constructor(private root: AVLNode<T> = null) { }
 
-  public insert(node: AVLNode<T>): boolean { }
-  public search(node: AVLNode<T>): boolean { }
-  public delete(node: AVLNode<T>): boolean { }
+  public insert(node: AVLNode<T>): boolean {
+    // TODO: Implement insert
+    return true;
+  }
+  public search(node: AVLNode<T>): boolean {
+    // TODO: Implement search
+    return true;
+  }
+  public delete(node: AVLNode<T>): boolean {
+    // TODO: Implement delete
+    return true;
+  }
 
   private detectRotation(node: AVLNode<T>): void { }
   private leftRotation(node: AVLNode<T>): void { }

From 32f25efb715087a6581107c98ff4f9a5941e930e Mon Sep 17 00:00:00 2001
From: Abhishek Prakash <abhishekabby@gmail.com>
Date: Wed, 19 Aug 2020 21:18:37 +0200
Subject: [PATCH 5/6] adding insert tests

---
 src/avl-tree/__test__/avl.spec.ts | 53 ++++++++++++++++++++++++++++
 src/avl-tree/avl-node.ts          | 25 +++++++++++++
 src/avl-tree/avl.ts               | 58 ++++++++++++++++++++++++++-----
 3 files changed, 128 insertions(+), 8 deletions(-)
 create mode 100644 src/avl-tree/__test__/avl.spec.ts

diff --git a/src/avl-tree/__test__/avl.spec.ts b/src/avl-tree/__test__/avl.spec.ts
new file mode 100644
index 0000000..0d7c1d6
--- /dev/null
+++ b/src/avl-tree/__test__/avl.spec.ts
@@ -0,0 +1,53 @@
+import { AVLTree } from "../avl"
+import { AVLNode } from "../avl-node";
+
+class Int extends AVLNode<number> {
+  constructor(value: number) {
+    super(value)
+  }
+
+  public compareTo(o: AVLNode<number>): number {
+    if (this.getValue() < o.getValue()) {
+      return -1;
+    } else if (this.getValue() > o.getValue()) {
+      return 1;
+    } else {
+      return 0;
+    }
+  }
+}
+
+describe("AVL Tree", () => {
+  describe("Insert operation", () => {
+    const avlTree = new AVLTree<number>();
+
+    it("should have null node", () => {
+      const root = avlTree.getRoot();
+      expect(root).toBe(null);
+    });
+
+    it("should add a node as root node in an empty tree", () => {
+      const isNodeInsterted = avlTree.insert(new Int(5));
+      const root = avlTree.getRoot();
+      expect(isNodeInsterted).toBeTruthy();
+      expect(root.getValue()).toBe(5);
+      expect(root.nodeHeight()).toBe(0);
+    });
+
+    it("should add a left child to the avl tree", () => {
+      const isNodeInsterted = avlTree.insert(new Int(3));
+      const left = avlTree.getRoot().getLeft();
+      expect(isNodeInsterted).toBeTruthy();
+      expect(left.getValue()).toBe(3);
+      expect(avlTree.getRoot().nodeHeight()).toBe(1);
+    });
+
+    it("should add a right child to the avl tree", () => {
+      const isNodeInsterted = avlTree.insert(new Int(9));
+      const right = avlTree.getRoot().getRight();
+      expect(isNodeInsterted).toBeTruthy();
+      expect(right.getValue()).toBe(9);
+      expect(avlTree.getRoot().nodeHeight()).toBe(1);
+    });
+  })
+})
\ No newline at end of file
diff --git a/src/avl-tree/avl-node.ts b/src/avl-tree/avl-node.ts
index e14079a..41c4e36 100644
--- a/src/avl-tree/avl-node.ts
+++ b/src/avl-tree/avl-node.ts
@@ -4,10 +4,13 @@ export abstract class AVLNode<T> {
   private leftHeight: number;
   private rightHeight: number;
   private value: number;
+  private parent: AVLNode<T>
+
 
   constructor(value: number) {
     this.left = null;
     this.right = null;
+    this.parent = null;
     this.leftHeight = 0;
     this.rightHeight = 0;
     this.value = value;
@@ -21,6 +24,20 @@ export abstract class AVLNode<T> {
     return (this.rightHeight > this.leftHeight) ? this.rightHeight : this.leftHeight;
   }
 
+  public setNodeHeights(): void {
+    if (this.right == null) {
+      this.rightHeight = 0;
+    } else {
+      this.rightHeight = this.right.nodeHeight() + 1;
+    }
+
+    if (this.left == null) {
+      this.leftHeight = 0;
+    } else {
+      this.leftHeight = this.left.nodeHeight() + 1;
+    }
+  }
+
   public abstract compareTo(o: AVLNode<number>): number
 
   /* #region(collapsed) Getter and Setter */
@@ -59,6 +76,14 @@ export abstract class AVLNode<T> {
   public getValue(): number {
     return this.value;
   }
+  public getParent(): AVLNode<T> {
+    return this.parent;
+  }
+
+  public setParent(parent: AVLNode<T>): void {
+    this.parent = parent;
+  }
+
   /* #endregion */
 
 }
\ No newline at end of file
diff --git a/src/avl-tree/avl.ts b/src/avl-tree/avl.ts
index fd22c2f..684a000 100644
--- a/src/avl-tree/avl.ts
+++ b/src/avl-tree/avl.ts
@@ -9,10 +9,33 @@ export interface IAVLTree<T> {
 export class AVLTree<T> implements IAVLTree<T> {
   constructor(private root: AVLNode<T> = null) { }
 
-  public insert(node: AVLNode<T>): boolean {
-    // TODO: Implement insert
-    return true;
+  public insert(node: AVLNode<T>, root: AVLNode<T> = this.root): boolean {
+    if (root == null) {
+      this.root = node;
+      return true;
+    }
+
+    if (node.compareTo(root) === 0) {
+      return false;
+    } else if (node.compareTo(root) > 0) {
+      if (root.getRight() == null) {
+        root.setRight(node);
+        this.updateNodeAfterInsert(node, root);
+        return true;
+      } else {
+        return this.insert(node, root.getRight());
+      }
+    } else {
+      if (root.getLeft() == null) {
+        root.setLeft(node);
+        this.updateNodeAfterInsert(node, root);
+        return true;
+      } else {
+        return this.insert(node, root.getLeft());
+      }
+    }
   }
+
   public search(node: AVLNode<T>): boolean {
     // TODO: Implement search
     return true;
@@ -22,9 +45,28 @@ export class AVLTree<T> implements IAVLTree<T> {
     return true;
   }
 
-  private detectRotation(node: AVLNode<T>): void { }
-  private leftRotation(node: AVLNode<T>): void { }
-  private rightRotation(node: AVLNode<T>): void { }
-  private leftRightRotation(node: AVLNode<T>): void { }
-  private rightLeftRotation(node: AVLNode<T>): void { }
+  public getRoot(): AVLNode<T> {
+    return this.root;
+  }
+
+  private updateNodeAfterInsert(node: AVLNode<T>, parent: AVLNode<T>): void {
+    node.setParent(parent);
+    node.setNodeHeights();
+    parent.setNodeHeights()
+  }
+  private detectRotation(node: AVLNode<T>): void {
+    // TODO: add logic
+  }
+  private leftRotation(node: AVLNode<T>): void {
+    // TODO: add logic
+  }
+  private rightRotation(node: AVLNode<T>): void {
+    // TODO: add logic
+  }
+  private leftRightRotation(node: AVLNode<T>): void {
+    // TODO: add logic
+  }
+  private rightLeftRotation(node: AVLNode<T>): void {
+    // TODO: add logic
+  }
 }
\ No newline at end of file

From 8a8207fb31638b83f61ee17d47e4d278a798cf5d Mon Sep 17 00:00:00 2001
From: Abhishek Prakash <abhishekabby@gmail.com>
Date: Thu, 4 Feb 2021 10:09:54 +0100
Subject: [PATCH 6/6] added unit test for same value check in avl

---
 src/avl-tree/__test__/avl.spec.ts | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/avl-tree/__test__/avl.spec.ts b/src/avl-tree/__test__/avl.spec.ts
index 0d7c1d6..67e0da3 100644
--- a/src/avl-tree/__test__/avl.spec.ts
+++ b/src/avl-tree/__test__/avl.spec.ts
@@ -49,5 +49,10 @@ describe("AVL Tree", () => {
       expect(right.getValue()).toBe(9);
       expect(avlTree.getRoot().nodeHeight()).toBe(1);
     });
+
+    it("should not add node with the same value", () => {
+      const isNodeInsterted = avlTree.insert(new Int(9));
+      expect(isNodeInsterted).toBeFalsy();
+    })
   })
 })
\ No newline at end of file