From d6be33842c86ed0df2456948cd2de22cedb7ebc9 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Mon, 2 Apr 2018 17:50:56 +0300 Subject: [PATCH] Add binary search tree. --- .eslintrc | 3 +- README.md | 1 + src/data-structures/tree/BinaryTreeNode.js | 37 ++++++++++++++++ .../tree/__test__/BinaryTreeNode.test.js | 38 ++++++++++++++++ .../binary-search-tree/BinarySearchTree.js | 19 ++++++++ .../BinarySearchTreeNode.js | 38 ++++++++++++++++ .../__test__/BinarySearchTree.test.js | 5 +++ .../__test__/BinarySearchTreeNode.test.js | 44 +++++++++++++++++++ 8 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 src/data-structures/tree/BinaryTreeNode.js create mode 100644 src/data-structures/tree/__test__/BinaryTreeNode.test.js create mode 100644 src/data-structures/tree/binary-search-tree/BinarySearchTree.js create mode 100644 src/data-structures/tree/binary-search-tree/BinarySearchTreeNode.js create mode 100644 src/data-structures/tree/binary-search-tree/__test__/BinarySearchTree.test.js create mode 100644 src/data-structures/tree/binary-search-tree/__test__/BinarySearchTreeNode.test.js diff --git a/.eslintrc b/.eslintrc index 3790cd52..29137996 100644 --- a/.eslintrc +++ b/.eslintrc @@ -6,6 +6,7 @@ "jest/globals": true }, "rules": { - "no-bitwise": "off" + "no-bitwise": "off", + "no-lonely-if": "off" } } diff --git a/README.md b/README.md index f5ffe8ad..75a6a06e 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ 4. [Hash Table](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/hash-table) 5. [Heap](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/heap) 5. [Trie](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/trie) +6. [Binary Search Tree](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/binary-search-tree) ## [Algorithms](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms) diff --git a/src/data-structures/tree/BinaryTreeNode.js b/src/data-structures/tree/BinaryTreeNode.js new file mode 100644 index 00000000..a85e04d2 --- /dev/null +++ b/src/data-structures/tree/BinaryTreeNode.js @@ -0,0 +1,37 @@ +export default class BinaryTreeNode { + constructor(value = null, left = null, right = null) { + this.left = left; + this.right = right; + this.value = value; + } + + addLeft(node) { + this.left = node; + return this; + } + + addRight(node) { + this.right = node; + return this; + } + + hasLeft() { + return !!this.left; + } + + hasRight() { + return !!this.right; + } + + traverseInOrder() { + return Array.prototype.concat( + this.left ? this.left.traverseInOrder() : [null], + [this.value], + this.right ? this.right.traverseInOrder() : [null], + ); + } + + toString() { + return this.traverseInOrder().filter(value => !!value).toString(); + } +} diff --git a/src/data-structures/tree/__test__/BinaryTreeNode.test.js b/src/data-structures/tree/__test__/BinaryTreeNode.test.js new file mode 100644 index 00000000..08e8cfd2 --- /dev/null +++ b/src/data-structures/tree/__test__/BinaryTreeNode.test.js @@ -0,0 +1,38 @@ +import BinaryTreeNode from '../BinaryTreeNode'; + +describe('BinaryTreeNode', () => { + it('should create node', () => { + const node = new BinaryTreeNode(); + + expect(node).toBeDefined(); + + expect(node.value).toBeNull(); + expect(node.left).toBeNull(); + expect(node.right).toBeNull(); + + expect(node.hasLeft()).toBeFalsy(); + expect(node.hasRight()).toBeFalsy(); + + const leftNode = new BinaryTreeNode(1); + const rightNode = new BinaryTreeNode(3); + const rootNode = new BinaryTreeNode(2); + + rootNode + .addLeft(leftNode) + .addRight(rightNode); + + expect(rootNode.value).toBe(2); + expect(rootNode.left.value).toBe(1); + expect(rootNode.right.value).toBe(3); + }); + + it('should traverse node', () => { + const leftNode = new BinaryTreeNode(1); + const rightNode = new BinaryTreeNode(3); + const rootNode = new BinaryTreeNode(2, leftNode, rightNode); + + expect(rootNode.traverseInOrder()).toEqual([null, 1, null, 2, null, 3, null]); + + expect(rootNode.toString()).toBe('1,2,3'); + }); +}); diff --git a/src/data-structures/tree/binary-search-tree/BinarySearchTree.js b/src/data-structures/tree/binary-search-tree/BinarySearchTree.js new file mode 100644 index 00000000..b7c06b4d --- /dev/null +++ b/src/data-structures/tree/binary-search-tree/BinarySearchTree.js @@ -0,0 +1,19 @@ +import BinarySearchTreeNode from './BinarySearchTreeNode'; + +export default class BinarySearchTree { + constructor() { + this.root = new BinarySearchTreeNode(); + } + + insert(value) { + this.root.insert(value); + } + + contains(value) { + return this.root.contains(value); + } + + toString() { + this.root.toString(); + } +} diff --git a/src/data-structures/tree/binary-search-tree/BinarySearchTreeNode.js b/src/data-structures/tree/binary-search-tree/BinarySearchTreeNode.js new file mode 100644 index 00000000..6f1eec55 --- /dev/null +++ b/src/data-structures/tree/binary-search-tree/BinarySearchTreeNode.js @@ -0,0 +1,38 @@ +import BinaryTreeNode from '../BinaryTreeNode'; + +export default class BinarySearchTreeNode extends BinaryTreeNode { + insert(value) { + if (value < this.value) { + // Insert to the left. + if (this.left) { + this.left.insert(value); + } else { + this.left = new BinarySearchTreeNode(value); + } + } else { + // Insert to the right. + if (this.right) { + this.right.insert(value); + } else { + this.right = new BinarySearchTreeNode(value); + } + } + + return this; + } + + contains(value) { + // Check the root. + if (this.value === value) { + return true; + } + + if (value < this.value && this.left) { + return this.left.contains(value); + } else if (this.right) { + return this.right.contains(value); + } + + return false; + } +} diff --git a/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTree.test.js b/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTree.test.js new file mode 100644 index 00000000..ae823edd --- /dev/null +++ b/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTree.test.js @@ -0,0 +1,5 @@ +describe('BinarySearchTree', () => { + it('should create binary search tree', () => { + + }); +}); diff --git a/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTreeNode.test.js b/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTreeNode.test.js new file mode 100644 index 00000000..0ff84dfd --- /dev/null +++ b/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTreeNode.test.js @@ -0,0 +1,44 @@ +import BinarySearchTreeNode from '../BinarySearchTreeNode'; + +describe('BinarySearchTreeNode', () => { + it('should create binary search tree', () => { + const bstNode = new BinarySearchTreeNode(2); + + expect(bstNode.value).toBe(2); + expect(bstNode.left).toBeNull(); + expect(bstNode.right).toBeNull(); + }); + + it('should insert nodes in correct order', () => { + const bstNode = new BinarySearchTreeNode(2); + bstNode.insert(1); + + expect(bstNode.toString()).toBe('1,2'); + expect(bstNode.contains(1)).toBeTruthy(); + expect(bstNode.contains(3)).toBeFalsy(); + + bstNode.insert(3); + + expect(bstNode.toString()).toBe('1,2,3'); + expect(bstNode.contains(3)).toBeTruthy(); + expect(bstNode.contains(4)).toBeFalsy(); + + bstNode.insert(7); + + expect(bstNode.toString()).toBe('1,2,3,7'); + expect(bstNode.contains(7)).toBeTruthy(); + expect(bstNode.contains(8)).toBeFalsy(); + + bstNode.insert(4); + + expect(bstNode.toString()).toBe('1,2,3,4,7'); + expect(bstNode.contains(4)).toBeTruthy(); + expect(bstNode.contains(8)).toBeFalsy(); + + bstNode.insert(6); + + expect(bstNode.toString()).toBe('1,2,3,4,6,7'); + expect(bstNode.contains(6)).toBeTruthy(); + expect(bstNode.contains(8)).toBeFalsy(); + }); +});