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