mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-12-26 07:01:18 +08:00
BloomFilter minor fixes.
This commit is contained in:
parent
b33b1fe1bc
commit
610b120e27
@ -1,6 +1,6 @@
|
||||
export default class BloomFilter {
|
||||
/**
|
||||
* @param {number} size
|
||||
* @param {number} size - the size of the storage.
|
||||
*/
|
||||
constructor(size = 100) {
|
||||
// Bloom filter size directly affects the likelihood of false positives.
|
||||
@ -15,7 +15,7 @@ export default class BloomFilter {
|
||||
insert(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));
|
||||
}
|
||||
|
||||
@ -26,8 +26,8 @@ export default class BloomFilter {
|
||||
mayContain(item) {
|
||||
const hashValues = this.getHashValues(item);
|
||||
|
||||
for (let i = 0; i < hashValues.length; i += 1) {
|
||||
if (!this.storage.getValue(hashValues[i])) {
|
||||
for (let hashIndex = 0; hashIndex < hashValues.length; hashIndex += 1) {
|
||||
if (!this.storage.getValue(hashValues[hashIndex])) {
|
||||
// We know that the item was definitely not inserted.
|
||||
return false;
|
||||
}
|
||||
@ -50,7 +50,7 @@ export default class BloomFilter {
|
||||
const storage = [];
|
||||
|
||||
// Initialize all indexes to false
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
for (let storageCellIndex = 0; storageCellIndex < size; storageCellIndex += 1) {
|
||||
storage.push(false);
|
||||
}
|
||||
|
||||
@ -67,14 +67,14 @@ export default class BloomFilter {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @param {string} item
|
||||
* @return {number}
|
||||
*/
|
||||
hash1(str) {
|
||||
hash1(item) {
|
||||
let hash = 0;
|
||||
|
||||
for (let i = 0; i < str.length; i += 1) {
|
||||
const char = str.charCodeAt(i);
|
||||
for (let charIndex = 0; charIndex < item.length; charIndex += 1) {
|
||||
const char = item.charCodeAt(charIndex);
|
||||
hash = (hash << 5) + hash + char;
|
||||
hash &= hash; // Convert to 32bit integer
|
||||
hash = Math.abs(hash);
|
||||
@ -84,44 +84,48 @@ export default class BloomFilter {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @param {string} item
|
||||
* @return {number}
|
||||
*/
|
||||
hash2(str) {
|
||||
hash2(item) {
|
||||
let hash = 5381;
|
||||
|
||||
for (let i = 0; i < str.length; i += 1) {
|
||||
const char = str.charCodeAt(i);
|
||||
for (let charIndex = 0; charIndex < item.length; charIndex += 1) {
|
||||
const char = item.charCodeAt(charIndex);
|
||||
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}
|
||||
*/
|
||||
hash3(str) {
|
||||
hash3(item) {
|
||||
let hash = 0;
|
||||
|
||||
for (let i = 0; i < str.length; i += 1) {
|
||||
const char = str.charCodeAt(i);
|
||||
for (let charIndex = 0; charIndex < item.length; charIndex += 1) {
|
||||
const char = item.charCodeAt(charIndex);
|
||||
hash = (hash << 5) - hash;
|
||||
hash += char;
|
||||
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[]}
|
||||
*/
|
||||
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';
|
||||
|
||||
describe('Bloom Filter', () => {
|
||||
describe('BloomFilter', () => {
|
||||
let bloomFilter;
|
||||
const people = ['Bruce Wayne', 'Clark Kent', 'Barry Allen'];
|
||||
const people = [
|
||||
'Bruce Wayne',
|
||||
'Clark Kent',
|
||||
'Barry Allen',
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
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.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);
|
||||
expect(typeof store.getValue).toBe('function');
|
||||
expect(typeof store.setValue).toBe('function');
|
||||
});
|
||||
|
||||
it('Should hash deterministically with all 3 hash functions', () => {
|
||||
const str = 'abc';
|
||||
expect(bloomFilter.hash1(str)).toEqual(bloomFilter.hash1(str));
|
||||
expect(bloomFilter.hash2(str)).toEqual(bloomFilter.hash2(str));
|
||||
expect(bloomFilter.hash3(str)).toEqual(bloomFilter.hash3(str));
|
||||
it('should hash deterministically with all 3 hash functions', () => {
|
||||
const str1 = 'apple';
|
||||
|
||||
expect(bloomFilter.hash1(str1)).toEqual(bloomFilter.hash1(str1));
|
||||
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', () => {
|
||||
expect(bloomFilter.getHashValues('abc').length).toEqual(3);
|
||||
it('should create an array with 3 hash values', () => {
|
||||
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));
|
||||
expect(bloomFilter.mayContain('Bruce Wayne')).toBe(true);
|
||||
expect(bloomFilter.mayContain('Clark Kent')).toBe(true);
|
||||
expect(bloomFilter.mayContain('Barry Allen')).toBe(true);
|
||||
|
||||
expect(bloomFilter.mayContain('Bruce Wayne')).toBeTruthy();
|
||||
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