diff --git a/TOC.md b/TOC.md index 09a67ec7..2cac390f 100644 --- a/TOC.md +++ b/TOC.md @@ -50,6 +50,8 @@ - [K Largest Elements](src/_DataStructures_/Heaps/k-largest-in-array) - [K Smallest Elements](src/_DataStructures_/Heaps/k-smallest-in-array) - [Hash Table](src/_DataStructures_/HashTable) +- [Set](src/_DataStructures_/Set) +- [Bloom Filters](src/_DataStructures_/BloomFilters) ### Logical Problems diff --git a/src/_DataStructures_/BloomFilters/index.js b/src/_DataStructures_/BloomFilters/index.js new file mode 100644 index 00000000..7e92b7dc --- /dev/null +++ b/src/_DataStructures_/BloomFilters/index.js @@ -0,0 +1,97 @@ +class BloomFilters { + constructor(size = 101) { + this.size = size; + this.data = this.getStorage(size); + } + + add(element) { + const indices = this.getIndices(element); + + for (let i = 0; i < indices.length; i += 1) { + this.data.setBit(indices[i]); + } + } + + contains(element) { + const indices = this.getIndices(element); + + for (let i = 0; i < indices.length; i += 1) { + const index = indices[i]; + if (!this.data.getBit(index)) { + return false; // item is definately not there + } + } + return true; // item may be there + } + + getIndices(element) { + return [this.hashOne(element), this.hashTwo(element), this.hashThree(element)]; + } + + hashOne(value) { + const stringValue = String(value); + let hashVal = 0; + + for (let i = 0; i < stringValue.length; i += 1) { + hashVal += stringValue.charCodeAt(i) - 96; + } + + // eslint-disable-next-line no-bitwise + hashVal &= hashVal; + + return Math.abs(hashVal % this.size); + } + + hashTwo(value) { + const stringValue = String(value); + const PRIME_MULTIPLIER = 1801; // Random prime number + let hashVal = 0; + + for (let i = 0; i < stringValue.length; i += 1) { + hashVal += stringValue.charCodeAt(i) - 96; + hashVal *= PRIME_MULTIPLIER; + } + + return Math.abs(hashVal % this.size); + } + + hashThree(value) { + const stringValue = String(value); + const PRIME_MULTIPLIER = 1801; // Random prime number + const PRIME_ADDER = 2029; // Random prime number + let hashVal = 0; + + for (let i = 0; i < stringValue.length; i += 1) { + hashVal += stringValue.charCodeAt(i) - 96; + hashVal *= PRIME_MULTIPLIER; + hashVal += PRIME_ADDER; + } + // eslint-disable-next-line no-bitwise + hashVal &= hashVal; + return Math.abs(hashVal % this.size); + } + + // eslint-disable-next-line class-methods-use-this + getStorage(size) { + const data = new Array(size).fill(0); + + return { + setBit(index) { + data[index] = 1; + }, + getBit(index) { + return data[index]; + }, + }; + } +} + +// const b = new BloomFilters(); + +// b.add('React.js'); +// b.add('Node.js'); + +// console.log(b.contains('JavaScript')); +// console.log(b.contains('React.js')); + +module.exports = BloomFilters; diff --git a/src/_DataStructures_/HashTable/index.js b/src/_DataStructures_/HashTable/index.js index 0b1f543d..c9c01172 100644 --- a/src/_DataStructures_/HashTable/index.js +++ b/src/_DataStructures_/HashTable/index.js @@ -11,15 +11,15 @@ class HashTable { this.threshold = 0.7; // the main bucket this.bucket = new Array(this.slot); + // fill the bucket with null + // for (let i = 0; i < this.slot; i += 1) this.bucket[i] = null; + this.bucket.fill(null); this.allowResize = allowResize; this.strongHash = strongHash; if (custonHash) { // eslint-disable-next-line no-underscore-dangle this._hash = custonHash; } - - // fill the bucket with null - for (let i = 0; i < this.slot; i += 1) this.bucket[i] = null; } _hash(key) { @@ -36,12 +36,14 @@ class HashTable { for (let i = 0; i < loopTill; i += 1) { const char = stringKey[i]; const value = char.charCodeAt(0) - 96; - index = (index * PRIME_MULTIPLIER + value) % this.bucket.length; + // eslint-disable-next-line no-bitwise + index &= index; + index = index * PRIME_MULTIPLIER + value; if (this.strongHash) { - index = (index + PRIME_ADDER) % this.bucket.length; + index += PRIME_ADDER; } } - return index; + return Math.abs(index % this.bucket.length); } _resize() { diff --git a/src/_DataStructures_/Set/index.js b/src/_DataStructures_/Set/index.js new file mode 100644 index 00000000..3812c4e5 --- /dev/null +++ b/src/_DataStructures_/Set/index.js @@ -0,0 +1,77 @@ +// XSet because ES6 already has a Set class +class XSet { + constructor() { + this.data = this.getStore(); + } + + add(element) { + this.data.push(element); + } + + remove(element) { + this.data.pop(element); + } + + has(element) { + return this.data.contains(element); + } + + values() { + return this.data.val(); + } + + union(givenSet) { + const result = new Set(); + const firstSetValues = this.values(); + const givenSetValues = givenSet.values(); + + // eslint-disable-next-line no-restricted-syntax + for (const e of firstSetValues) result.add(e); + + // eslint-disable-next-line no-restricted-syntax + for (const e of givenSetValues) result.add(e); + + return result; + } + + // eslint-disable-next-line class-methods-use-this + getStore() { + const store = {}; + + return { + push(el) { + if (!store[el]) { + store[el] = true; + } + }, + pop(el) { + if (store[el]) { + delete store[el]; + } + }, + contains(el) { + return !!store[el]; + }, + val() { + return Object.keys(store); + }, + }; + } +} + +// const s = new XSet(); + +// s.add(10); +// s.add(20); +// s.add(90); + +// console.log(s.has(1)); +// console.log(s.has(10)); +// console.log(s.has(90)); + +// console.log(s.values()); +// s.remove(90); +// console.log(s.has(90)); +// console.log(s.data); + +module.exports = XSet;