From 9e5deb66951fc37f1ae340e1566a412598516e29 Mon Sep 17 00:00:00 2001 From: Hari Venugopalan Date: Wed, 20 Jun 2018 18:33:22 -0700 Subject: [PATCH 1/7] Implemented Z algorithm --- .../string/z-algorithm/zAlgorithm.js | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/algorithms/string/z-algorithm/zAlgorithm.js diff --git a/src/algorithms/string/z-algorithm/zAlgorithm.js b/src/algorithms/string/z-algorithm/zAlgorithm.js new file mode 100644 index 0000000000..b0a8480325 --- /dev/null +++ b/src/algorithms/string/z-algorithm/zAlgorithm.js @@ -0,0 +1,51 @@ +/** + * @param {string} word + * @param {string} text + * @return {number[]} + */ + +function buildZArray(word, text) { + let zString = word+"$+"text; + let zArray = new Array(zString.length); + let left = 0, right = 0, k = 0; + + for (let i = 1; i < zString.length; i++) { + if (i > right) { + left = right = 0; + while ( right Date: Wed, 20 Jun 2018 19:18:37 -0700 Subject: [PATCH 2/7] Fixed bugs in implementation and added tests --- .../z-algorithm/__test__/zAlgorithm.test.js | 12 +++++ .../string/z-algorithm/zAlgorithm.js | 52 +++++++++++-------- 2 files changed, 41 insertions(+), 23 deletions(-) create mode 100644 src/algorithms/string/z-algorithm/__test__/zAlgorithm.test.js diff --git a/src/algorithms/string/z-algorithm/__test__/zAlgorithm.test.js b/src/algorithms/string/z-algorithm/__test__/zAlgorithm.test.js new file mode 100644 index 0000000000..d58ff75bc9 --- /dev/null +++ b/src/algorithms/string/z-algorithm/__test__/zAlgorithm.test.js @@ -0,0 +1,12 @@ +import zAlgorithm from '../zAlgorithm'; + +describe('zAlgorithm', () => { + it('should find word position in given text', () => { + expect(zAlgorithm('abcbcglx', 'abca')).toBe(-1); + expect(zAlgorithm('abcbcglx', 'bcgl')).toBe(3); + expect(zAlgorithm('abcxabcdabxabcdabcdabcy', 'abcdabcy')).toBe(15); + expect(zAlgorithm('abcxabcdabxabcdabcdabcy', 'abcdabca')).toBe(-1); + expect(zAlgorithm('abcxabcdabxaabcdabcabcdabcdabcy', 'abcdabca')).toBe(12); + expect(zAlgorithm('abcxabcdabxaabaabaaaabcdabcdabcy', 'aabaabaaa')).toBe(11); + }); +}); diff --git a/src/algorithms/string/z-algorithm/zAlgorithm.js b/src/algorithms/string/z-algorithm/zAlgorithm.js index b0a8480325..f93318ce43 100644 --- a/src/algorithms/string/z-algorithm/zAlgorithm.js +++ b/src/algorithms/string/z-algorithm/zAlgorithm.js @@ -5,47 +5,53 @@ */ function buildZArray(word, text) { - let zString = word+"$+"text; - let zArray = new Array(zString.length); - let left = 0, right = 0, k = 0; + const zString = `${word}$${text}`; + const zArray = new Array(zString.length); + let left = 0; + let right = 0; + let k = 0; - for (let i = 1; i < zString.length; i++) { + for (let i = 1; i < zString.length; i += 1) { if (i > right) { - left = right = 0; - while ( right Date: Wed, 20 Jun 2018 19:36:38 -0700 Subject: [PATCH 3/7] Added README explaining z algorithm --- src/algorithms/string/z-algorithm/README.md | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/algorithms/string/z-algorithm/README.md diff --git a/src/algorithms/string/z-algorithm/README.md b/src/algorithms/string/z-algorithm/README.md new file mode 100644 index 0000000000..733ebf5cd1 --- /dev/null +++ b/src/algorithms/string/z-algorithm/README.md @@ -0,0 +1,27 @@ +# Z-algorithm + +The Z-algorithm finds occurrences of a "word" `W` +within a main "text string" `T` in linear time. + +Given a string `S` of length `n`, the algorithm produces +an array, `Z` where `Z[i]` represents the ongest substring +starting from `S[i]` which is also a prefix of `S`. Finding +`Z` for the string obtained by concatenating the word, `W` +with a nonce character, say `$` followed by the text, `T`, +helps with pattern matching, for if there is some index `i` +such that `Z[i]` equals the pattern length, then the pattern +must be present at that point. + +While the `Z` array can be computed with two nested loops, the +following strategy shows how to obtain it in linear time, based +on the idea that as we iterate over the letters in the string +(index `i` from `1` to `n - 1`), we maintain an interval `[L, R]` +which is the interval with maximum `R` such that `1 ≤ L ≤ i ≤ R` +and `S[L...R]` is a prefix that is also a substring (if no such +interval exists, just let `L = R =  - 1`). For `i = 1`, we can +simply compute `L` and `R` by comparing `S[0...]` to `S[1...]`. + +## Complexity + +- **Time:** `O(|W| + |T|)` +- **Space:** `O(|W|)` \ No newline at end of file From 0b195c8f4c8fa7a21a690c23a8e83f122d3e1f00 Mon Sep 17 00:00:00 2001 From: hariv Date: Mon, 2 Jul 2018 19:08:31 -0700 Subject: [PATCH 4/7] Created BTree and BTreeNode classes and added constructors --- src/data-structures/tree/b-tree/BTree.js | 6 ++++++ src/data-structures/tree/b-tree/BTreeNode.js | 9 +++++++++ src/data-structures/tree/b-tree/README.md | 0 3 files changed, 15 insertions(+) create mode 100644 src/data-structures/tree/b-tree/BTree.js create mode 100644 src/data-structures/tree/b-tree/BTreeNode.js create mode 100644 src/data-structures/tree/b-tree/README.md diff --git a/src/data-structures/tree/b-tree/BTree.js b/src/data-structures/tree/b-tree/BTree.js new file mode 100644 index 0000000000..da96713875 --- /dev/null +++ b/src/data-structures/tree/b-tree/BTree.js @@ -0,0 +1,6 @@ +export default class BTree { + constructor(degree = 0) { + this.root = null; + this.degree = degree; + } +} diff --git a/src/data-structures/tree/b-tree/BTreeNode.js b/src/data-structures/tree/b-tree/BTreeNode.js new file mode 100644 index 0000000000..eeb874f93e --- /dev/null +++ b/src/data-structures/tree/b-tree/BTreeNode.js @@ -0,0 +1,9 @@ +export default class BTreeNode { + constructor(degree = 0, isLeaf = true) { + this.degree = degree; + this.isLeaf = isLeaf; + this.keys = new Array((2 * this.degree) - 1); + this.children = new Array(2 * this.degree); + this.numKeys = 0; + } +} diff --git a/src/data-structures/tree/b-tree/README.md b/src/data-structures/tree/b-tree/README.md new file mode 100644 index 0000000000..e69de29bb2 From 54432b46b8bd205bcaed9b215634cb3be2b8f87b Mon Sep 17 00:00:00 2001 From: hariv Date: Tue, 3 Jul 2018 00:23:26 -0700 Subject: [PATCH 5/7] Added tree node traversal --- src/data-structures/tree/b-tree/BTreeNode.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/data-structures/tree/b-tree/BTreeNode.js b/src/data-structures/tree/b-tree/BTreeNode.js index eeb874f93e..d4797d2490 100644 --- a/src/data-structures/tree/b-tree/BTreeNode.js +++ b/src/data-structures/tree/b-tree/BTreeNode.js @@ -6,4 +6,19 @@ export default class BTreeNode { this.children = new Array(2 * this.degree); this.numKeys = 0; } + + traversal() { + let i; + let traverse = []; + for (i = 0; i < this.numKeys; i += 1) { + if (!this.isLeaf) { + traverse = traverse.concat(this.children[i].traversal()); + } + traverse.push(this.keys[i]); + } + if (!this.isLeaf) { + traverse = traverse.concat(this.children[i].traversal()); + } + return traverse; + } } From fedf84d18f0dc19d83aa82c848aefd3aea6f5a53 Mon Sep 17 00:00:00 2001 From: hariv Date: Tue, 3 Jul 2018 00:31:51 -0700 Subject: [PATCH 6/7] Added BTreeNode find method --- src/data-structures/tree/b-tree/BTreeNode.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/data-structures/tree/b-tree/BTreeNode.js b/src/data-structures/tree/b-tree/BTreeNode.js index d4797d2490..406a669895 100644 --- a/src/data-structures/tree/b-tree/BTreeNode.js +++ b/src/data-structures/tree/b-tree/BTreeNode.js @@ -1,3 +1,5 @@ +import Comparator from '../../../utils/comparator/Comparator'; + export default class BTreeNode { constructor(degree = 0, isLeaf = true) { this.degree = degree; @@ -5,6 +7,7 @@ export default class BTreeNode { this.keys = new Array((2 * this.degree) - 1); this.children = new Array(2 * this.degree); this.numKeys = 0; + this.nodeComparator = new Comparator(); } traversal() { @@ -21,4 +24,18 @@ export default class BTreeNode { } return traverse; } + + find(value) { + let i = 0; + while (i < this.numKeys && value > this.keys[i]) { + i += 1; + } + if (this.nodeComparator.equal(value, this.keys[i])) { + return this; + } + if (this.isLeaf) { + return null; + } + return this.children[i].find(value); + } } From 00b52b4f71d3b0347b97115fbbe5fd7760dae010 Mon Sep 17 00:00:00 2001 From: hariv Date: Tue, 3 Jul 2018 02:16:58 -0700 Subject: [PATCH 7/7] Added insert method --- src/data-structures/tree/b-tree/BTree.js | 24 +++++++++ src/data-structures/tree/b-tree/BTreeNode.js | 51 ++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/src/data-structures/tree/b-tree/BTree.js b/src/data-structures/tree/b-tree/BTree.js index da96713875..8c73938189 100644 --- a/src/data-structures/tree/b-tree/BTree.js +++ b/src/data-structures/tree/b-tree/BTree.js @@ -1,6 +1,30 @@ +import BTreeNode from './BTreeNode'; + export default class BTree { constructor(degree = 0) { this.root = null; this.degree = degree; } + + insert(value) { + if (this.root === null) { + this.root = new BTreeNode(this.degree, true); + this.root.keys[0] = value; + this.root.numKeys = 1; + } else { + if (root.numKeys === (2 * this.degree) - 1) { + let i = 0; + const newRoot = new BTreeNode(this.degree, false); + newRoot.children[0] = this.root; + newRoot.splitChild(0, this.root); + if (newRoot.keys[0] < value) { + i += 1; + } + newRoot.children[i].insert(value); + this.root = newRoot; + } else { + this.root.insert(value); + } + } + } } diff --git a/src/data-structures/tree/b-tree/BTreeNode.js b/src/data-structures/tree/b-tree/BTreeNode.js index 406a669895..125b92a21a 100644 --- a/src/data-structures/tree/b-tree/BTreeNode.js +++ b/src/data-structures/tree/b-tree/BTreeNode.js @@ -10,6 +10,10 @@ export default class BTreeNode { this.nodeComparator = new Comparator(); } + setKeys(value) { + this.numKeys = value; + } + traversal() { let i; let traverse = []; @@ -38,4 +42,51 @@ export default class BTreeNode { } return this.children[i].find(value); } + + insert(value) { + let i = this.numKeys - 1; + if (this.isLeaf) { + while (i >= 0 && this.keys[i] > value) { + this.keys[i + 1] = this.keys[i]; + i -= 1; + } + this.keys[i + 1] = value; + this.numKeys += 1; + } else { + while (i >= 0 && this.keys[i] > value) { + i -= 1; + } + if (this.children[i + 1].numKeys === (2 * this.degree) - 1) { + this.splitChild(i + 1, this.children[i + 1]); + if (this.keys[i + 1] < value) { + i += 1; + } + } + this.children[i + 1].insert(value); + } + } + + splitChild(i, node) { + const temp = new BTreeNode(node.degree, node.isLeaf); + let j; + temp.numKeys = this.degree - 1; + for (j = 0; j < this.degree - 1; j += 1) { + temp.keys[j] = node.keys[j + this.degree]; + } + if (!node.isLeaf) { + for (j = 0; j < this.degree; j += 1) { + temp.children[j] = node.children[j + this.degree]; + } + } + node.setKeys(this.degree - 1); + for (j = this.numKeys; j >= i + 1; j -= 1) { + this.children[j + 1] = this.children[j]; + } + this.children[i + 1] = temp; + for (j = this.numKeys - 1; j >= i; j -= 1) { + this.keys[j + 1] = this.keys[j]; + } + this.keys[i] = node.keys[this.degree - 1]; + this.numKeys = this.numKeys + 1; + } }