mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-12-26 23:21:18 +08:00
BloomFilter minor fixes.
This commit is contained in:
parent
b33b1fe1bc
commit
610b120e27
@ -1,6 +1,6 @@
|
|||||||
export default class BloomFilter {
|
export default class BloomFilter {
|
||||||
/**
|
/**
|
||||||
* @param {number} size
|
* @param {number} size - the size of the storage.
|
||||||
*/
|
*/
|
||||||
constructor(size = 100) {
|
constructor(size = 100) {
|
||||||
// Bloom filter size directly affects the likelihood of false positives.
|
// Bloom filter size directly affects the likelihood of false positives.
|
||||||
@ -15,7 +15,7 @@ export default class BloomFilter {
|
|||||||
insert(item) {
|
insert(item) {
|
||||||
const hashValues = this.getHashValues(item);
|
const hashValues = this.getHashValues(item);
|
||||||
|
|
||||||
// Set each hashValue index to true
|
// Set each hashValue index to true.
|
||||||
hashValues.forEach(val => this.storage.setValue(val));
|
hashValues.forEach(val => this.storage.setValue(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,8 +26,8 @@ export default class BloomFilter {
|
|||||||
mayContain(item) {
|
mayContain(item) {
|
||||||
const hashValues = this.getHashValues(item);
|
const hashValues = this.getHashValues(item);
|
||||||
|
|
||||||
for (let i = 0; i < hashValues.length; i += 1) {
|
for (let hashIndex = 0; hashIndex < hashValues.length; hashIndex += 1) {
|
||||||
if (!this.storage.getValue(hashValues[i])) {
|
if (!this.storage.getValue(hashValues[hashIndex])) {
|
||||||
// We know that the item was definitely not inserted.
|
// We know that the item was definitely not inserted.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ export default class BloomFilter {
|
|||||||
const storage = [];
|
const storage = [];
|
||||||
|
|
||||||
// Initialize all indexes to false
|
// Initialize all indexes to false
|
||||||
for (let i = 0; i < size; i += 1) {
|
for (let storageCellIndex = 0; storageCellIndex < size; storageCellIndex += 1) {
|
||||||
storage.push(false);
|
storage.push(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,14 +67,14 @@ export default class BloomFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} str
|
* @param {string} item
|
||||||
* @return {number}
|
* @return {number}
|
||||||
*/
|
*/
|
||||||
hash1(str) {
|
hash1(item) {
|
||||||
let hash = 0;
|
let hash = 0;
|
||||||
|
|
||||||
for (let i = 0; i < str.length; i += 1) {
|
for (let charIndex = 0; charIndex < item.length; charIndex += 1) {
|
||||||
const char = str.charCodeAt(i);
|
const char = item.charCodeAt(charIndex);
|
||||||
hash = (hash << 5) + hash + char;
|
hash = (hash << 5) + hash + char;
|
||||||
hash &= hash; // Convert to 32bit integer
|
hash &= hash; // Convert to 32bit integer
|
||||||
hash = Math.abs(hash);
|
hash = Math.abs(hash);
|
||||||
@ -84,44 +84,48 @@ export default class BloomFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} str
|
* @param {string} item
|
||||||
* @return {number}
|
* @return {number}
|
||||||
*/
|
*/
|
||||||
hash2(str) {
|
hash2(item) {
|
||||||
let hash = 5381;
|
let hash = 5381;
|
||||||
|
|
||||||
for (let i = 0; i < str.length; i += 1) {
|
for (let charIndex = 0; charIndex < item.length; charIndex += 1) {
|
||||||
const char = str.charCodeAt(i);
|
const char = item.charCodeAt(charIndex);
|
||||||
hash = (hash << 5) + hash + char; /* hash * 33 + c */
|
hash = (hash << 5) + hash + char; /* hash * 33 + c */
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash % this.size;
|
return Math.abs(hash % this.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} str
|
* @param {string} item
|
||||||
* @return {number}
|
* @return {number}
|
||||||
*/
|
*/
|
||||||
hash3(str) {
|
hash3(item) {
|
||||||
let hash = 0;
|
let hash = 0;
|
||||||
|
|
||||||
for (let i = 0; i < str.length; i += 1) {
|
for (let charIndex = 0; charIndex < item.length; charIndex += 1) {
|
||||||
const char = str.charCodeAt(i);
|
const char = item.charCodeAt(charIndex);
|
||||||
hash = (hash << 5) - hash;
|
hash = (hash << 5) - hash;
|
||||||
hash += char;
|
hash += char;
|
||||||
hash &= hash; // Convert to 32bit integer
|
hash &= hash; // Convert to 32bit integer
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash % this.size;
|
return Math.abs(hash % this.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs all 3 hash functions on the input and returns an array of results
|
* Runs all 3 hash functions on the input and returns an array of results.
|
||||||
*
|
*
|
||||||
* @param {string} str
|
* @param {string} item
|
||||||
* @return {number[]}
|
* @return {number[]}
|
||||||
*/
|
*/
|
||||||
getHashValues(item) {
|
getHashValues(item) {
|
||||||
return [this.hash1(item), Math.abs(this.hash2(item)), Math.abs(this.hash3(item))];
|
return [
|
||||||
|
this.hash1(item),
|
||||||
|
this.hash2(item),
|
||||||
|
this.hash3(item),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,62 @@
|
|||||||
import BloomFilter from '../BloomFilter';
|
import BloomFilter from '../BloomFilter';
|
||||||
|
|
||||||
describe('Bloom Filter', () => {
|
describe('BloomFilter', () => {
|
||||||
let bloomFilter;
|
let bloomFilter;
|
||||||
const people = ['Bruce Wayne', 'Clark Kent', 'Barry Allen'];
|
const people = [
|
||||||
|
'Bruce Wayne',
|
||||||
|
'Clark Kent',
|
||||||
|
'Barry Allen',
|
||||||
|
];
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
bloomFilter = new BloomFilter();
|
bloomFilter = new BloomFilter();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should have methods named "insert" and "mayContain"', () => {
|
it('should have methods named "insert" and "mayContain"', () => {
|
||||||
expect(typeof bloomFilter.insert).toBe('function');
|
expect(typeof bloomFilter.insert).toBe('function');
|
||||||
expect(typeof bloomFilter.mayContain).toBe('function');
|
expect(typeof bloomFilter.mayContain).toBe('function');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should create a new filter store with the appropriate methods', () => {
|
it('should create a new filter store with the appropriate methods', () => {
|
||||||
const store = bloomFilter.createStore(18);
|
const store = bloomFilter.createStore(18);
|
||||||
expect(typeof store.getValue).toBe('function');
|
expect(typeof store.getValue).toBe('function');
|
||||||
expect(typeof store.setValue).toBe('function');
|
expect(typeof store.setValue).toBe('function');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should hash deterministically with all 3 hash functions', () => {
|
it('should hash deterministically with all 3 hash functions', () => {
|
||||||
const str = 'abc';
|
const str1 = 'apple';
|
||||||
expect(bloomFilter.hash1(str)).toEqual(bloomFilter.hash1(str));
|
|
||||||
expect(bloomFilter.hash2(str)).toEqual(bloomFilter.hash2(str));
|
expect(bloomFilter.hash1(str1)).toEqual(bloomFilter.hash1(str1));
|
||||||
expect(bloomFilter.hash3(str)).toEqual(bloomFilter.hash3(str));
|
expect(bloomFilter.hash2(str1)).toEqual(bloomFilter.hash2(str1));
|
||||||
|
expect(bloomFilter.hash3(str1)).toEqual(bloomFilter.hash3(str1));
|
||||||
|
|
||||||
|
expect(bloomFilter.hash1(str1)).toBe(14);
|
||||||
|
expect(bloomFilter.hash2(str1)).toBe(43);
|
||||||
|
expect(bloomFilter.hash3(str1)).toBe(10);
|
||||||
|
|
||||||
|
const str2 = 'orange';
|
||||||
|
|
||||||
|
expect(bloomFilter.hash1(str2)).toEqual(bloomFilter.hash1(str2));
|
||||||
|
expect(bloomFilter.hash2(str2)).toEqual(bloomFilter.hash2(str2));
|
||||||
|
expect(bloomFilter.hash3(str2)).toEqual(bloomFilter.hash3(str2));
|
||||||
|
|
||||||
|
expect(bloomFilter.hash1(str2)).toBe(0);
|
||||||
|
expect(bloomFilter.hash2(str2)).toBe(61);
|
||||||
|
expect(bloomFilter.hash3(str2)).toBe(10);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should create an array with 3 hash values', () => {
|
it('should create an array with 3 hash values', () => {
|
||||||
expect(bloomFilter.getHashValues('abc').length).toEqual(3);
|
expect(bloomFilter.getHashValues('abc').length).toBe(3);
|
||||||
|
expect(bloomFilter.getHashValues('abc')).toEqual([66, 63, 54]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should insert strings correctly and return true when checking for inserted values', () => {
|
it('should insert strings correctly and return true when checking for inserted values', () => {
|
||||||
people.forEach(person => bloomFilter.insert(person));
|
people.forEach(person => bloomFilter.insert(person));
|
||||||
expect(bloomFilter.mayContain('Bruce Wayne')).toBe(true);
|
|
||||||
expect(bloomFilter.mayContain('Clark Kent')).toBe(true);
|
expect(bloomFilter.mayContain('Bruce Wayne')).toBeTruthy();
|
||||||
expect(bloomFilter.mayContain('Barry Allen')).toBe(true);
|
expect(bloomFilter.mayContain('Clark Kent')).toBeTruthy();
|
||||||
|
expect(bloomFilter.mayContain('Barry Allen')).toBeTruthy();
|
||||||
|
|
||||||
|
expect(bloomFilter.mayContain('Tony Stark')).toBeFalsy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user