Skip to content

Commit 76e9311

Browse files
authored
Merge branch 'master' into lru_improve
2 parents 2db7b30 + 8db9d10 commit 76e9311

File tree

2 files changed

+87
-7
lines changed

2 files changed

+87
-7
lines changed

src/main/java/com/thealgorithms/datastructures/bloomfilter/BloomFilter.java

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
/**
66
* A generic BloomFilter implementation for probabilistic membership checking.
7+
* <p>
8+
* Bloom filters are space-efficient data structures that provide a fast way to test whether an
9+
* element is a member of a set. They may produce false positives, indicating an element is
10+
* in the set when it is not, but they will never produce false negatives.
11+
* </p>
712
*
813
* @param <T> The type of elements to be stored in the Bloom filter.
914
*/
@@ -17,18 +22,22 @@ public class BloomFilter<T> {
1722
* Constructs a BloomFilter with a specified number of hash functions and bit array size.
1823
*
1924
* @param numberOfHashFunctions the number of hash functions to use
20-
* @param bitArraySize the size of the bit array
25+
* @param bitArraySize the size of the bit array, which determines the capacity of the filter
26+
* @throws IllegalArgumentException if numberOfHashFunctions or bitArraySize is less than 1
2127
*/
2228
@SuppressWarnings("unchecked")
2329
public BloomFilter(int numberOfHashFunctions, int bitArraySize) {
30+
if (numberOfHashFunctions < 1 || bitArraySize < 1) {
31+
throw new IllegalArgumentException("Number of hash functions and bit array size must be greater than 0");
32+
}
2433
this.numberOfHashFunctions = numberOfHashFunctions;
2534
this.bitArray = new BitSet(bitArraySize);
2635
this.hashFunctions = new Hash[numberOfHashFunctions];
2736
initializeHashFunctions();
2837
}
2938

3039
/**
31-
* Initializes the hash functions with unique indices.
40+
* Initializes the hash functions with unique indices to ensure different hashing.
3241
*/
3342
private void initializeHashFunctions() {
3443
for (int i = 0; i < numberOfHashFunctions; i++) {
@@ -38,8 +47,12 @@ private void initializeHashFunctions() {
3847

3948
/**
4049
* Inserts an element into the Bloom filter.
50+
* <p>
51+
* This method hashes the element using all defined hash functions and sets the corresponding
52+
* bits in the bit array.
53+
* </p>
4154
*
42-
* @param key the element to insert
55+
* @param key the element to insert into the Bloom filter
4356
*/
4457
public void insert(T key) {
4558
for (Hash<T> hash : hashFunctions) {
@@ -50,8 +63,13 @@ public void insert(T key) {
5063

5164
/**
5265
* Checks if an element might be in the Bloom filter.
66+
* <p>
67+
* This method checks the bits at the positions computed by each hash function. If any of these
68+
* bits are not set, the element is definitely not in the filter. If all bits are set, the element
69+
* might be in the filter.
70+
* </p>
5371
*
54-
* @param key the element to check
72+
* @param key the element to check for membership in the Bloom filter
5573
* @return {@code true} if the element might be in the Bloom filter, {@code false} if it is definitely not
5674
*/
5775
public boolean contains(T key) {
@@ -66,6 +84,9 @@ public boolean contains(T key) {
6684

6785
/**
6886
* Inner class representing a hash function used by the Bloom filter.
87+
* <p>
88+
* Each instance of this class represents a different hash function based on its index.
89+
* </p>
6990
*
7091
* @param <T> The type of elements to be hashed.
7192
*/
@@ -76,27 +97,35 @@ private static class Hash<T> {
7697
/**
7798
* Constructs a Hash function with a specified index.
7899
*
79-
* @param index the index of this hash function
100+
* @param index the index of this hash function, used to create a unique hash
80101
*/
81102
Hash(int index) {
82103
this.index = index;
83104
}
84105

85106
/**
86107
* Computes the hash of the given key.
108+
* <p>
109+
* The hash value is calculated by multiplying the index of the hash function
110+
* with the ASCII sum of the string representation of the key.
111+
* </p>
87112
*
88113
* @param key the element to hash
89-
* @return the hash value
114+
* @return the computed hash value
90115
*/
91116
public int compute(T key) {
92117
return index * asciiString(String.valueOf(key));
93118
}
94119

95120
/**
96121
* Computes the ASCII value sum of the characters in a string.
122+
* <p>
123+
* This method iterates through each character of the string and accumulates
124+
* their ASCII values to produce a single integer value.
125+
* </p>
97126
*
98127
* @param word the string to compute
99-
* @return the sum of ASCII values of the characters
128+
* @return the sum of ASCII values of the characters in the string
100129
*/
101130
private int asciiString(String word) {
102131
int sum = 0;

src/test/java/com/thealgorithms/datastructures/bloomfilter/BloomFilterTest.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,55 @@ void testMultipleInsertions() {
6262

6363
Assertions.assertFalse(bloomFilter.contains("key" + 200));
6464
}
65+
66+
@Test
67+
void testEmptyFilterContains() {
68+
Assertions.assertFalse(bloomFilter.contains("notInserted"), "Filter should not contain any elements when empty");
69+
Assertions.assertFalse(bloomFilter.contains(null), "Filter should not contain null elements");
70+
}
71+
72+
@Test
73+
void testDifferentTypes() {
74+
BloomFilter<Object> filter = new BloomFilter<>(3, 100);
75+
filter.insert("string");
76+
filter.insert(123);
77+
filter.insert(45.67);
78+
79+
Assertions.assertTrue(filter.contains("string"), "Filter should contain the string 'string'");
80+
Assertions.assertTrue(filter.contains(123), "Filter should contain the integer 123");
81+
Assertions.assertTrue(filter.contains(45.67), "Filter should contain the double 45.67");
82+
Assertions.assertFalse(filter.contains("missing"), "Filter should not contain elements that were not inserted");
83+
}
84+
85+
@Test
86+
void testFalsePositiveAfterInsertions() {
87+
bloomFilter.insert("cat");
88+
bloomFilter.insert("dog");
89+
bloomFilter.insert("fish");
90+
91+
// Checking for an element that was not added
92+
Assertions.assertFalse(bloomFilter.contains("bird"), "Filter should not contain 'bird' which was never inserted");
93+
94+
// To increase chances of false positives, we can add more items
95+
for (int i = 0; i < 100; i++) {
96+
bloomFilter.insert("item" + i);
97+
}
98+
99+
Assertions.assertFalse(bloomFilter.contains("nonexistent"), "Filter should not contain 'nonexistent' which was never inserted");
100+
}
101+
102+
@Test
103+
void testBoundaryConditions() {
104+
BloomFilter<String> filter = new BloomFilter<>(3, 10);
105+
filter.insert("a");
106+
filter.insert("b");
107+
filter.insert("c");
108+
filter.insert("d");
109+
110+
Assertions.assertTrue(filter.contains("a"), "Filter should contain 'a'");
111+
Assertions.assertTrue(filter.contains("b"), "Filter should contain 'b'");
112+
Assertions.assertTrue(filter.contains("c"), "Filter should contain 'c'");
113+
Assertions.assertTrue(filter.contains("d"), "Filter should contain 'd'");
114+
Assertions.assertFalse(filter.contains("e"), "Filter should not contain 'e' which was not inserted");
115+
}
65116
}

0 commit comments

Comments
 (0)