@@ -12,9 +12,11 @@ public class HashFunction implements Hash {
12
12
13
13
14
14
public HashFunction (){}
15
-
15
+
16
+ @ Override
16
17
public void print () {}
17
-
18
+
19
+ @ Override
18
20
public int getHashCode (String key ){
19
21
return 0 ;
20
22
}
@@ -44,25 +46,55 @@ public static int fnv1Hash(String key, int m){
44
46
}
45
47
46
48
/**
47
- * Returns an array of k hashes by computing linear
48
- * combinations of the fnv1 hash with the MurmurHash
49
- *
50
- * @param key Key in which the hash will be performed on
51
- * @param k Value specifying how many hash values to compute
52
- * @param m Modulus value
53
- * @return An array of size K with hash values [0, m-1]
49
+ * Returns an array of k hashes by computing linear combinations of the fnv1 hash with the
50
+ * MurmurHash
51
+ *
52
+ * @param key Key in which the hash will be performed on
53
+ * @param k Value specifying how many hash values to compute
54
+ * @param m Modulus value; m should be much larger than k
55
+ * @return An array of size K with hash values [0, m-1]
54
56
*/
55
- public int [] hash (String key ,int k , int m ){
57
+ @ Override
58
+ public int [] hash (String key , int k , int m ) {
56
59
int [] hashes = new int [k ];
57
- for (int ii = 0 ; ii < k ; ii ++){
58
- long h1 = fnv1Hash (key );
59
- long h2 = murmurHash (key );
60
- long axb = h1 +(ii *h2 );
61
- hashes [ii ] = (int )(axb % m );
60
+ long h1 = fnv1Hash (key );
61
+ long h2 = murmurHash (key );
62
+ for (int ii = 0 ; ii < k ; ii ++ ) {
63
+ long axb = ii + h1 + (ii * h2 );
64
+ int hashCandidate = (int ) (axb % m );
65
+ int iterations = 0 ;
66
+ // Check that the generated hash candidate was not generated before.
67
+ while (iterations < m && contains (hashes , hashCandidate , ii )) {
68
+ // Try to find a new hash candidate that is not yet in the array.
69
+ hashCandidate = (int ) ((hashCandidate + murmurHash (Integer .toString (iterations + hashCandidate ))) % m );
70
+ iterations ++ ;
71
+ }
72
+ if (iterations >= m ) {
73
+ throw new RuntimeException ("Failed to generate distinct hashes for: " + key );
74
+ }
75
+ hashes [ii ] = hashCandidate ;
62
76
}
63
77
return hashes ;
64
78
}
65
-
79
+
80
+ /**
81
+ * Checks if a value is contained in an array.
82
+ *
83
+ * @param array The array to search in
84
+ * @param valueToFind The value to find in the array
85
+ * @param lastIndex The last index of the array that is checked
86
+ * @return <code>true</code> if the value was found, <code>false</code> otherwise
87
+ */
88
+ private static boolean contains (final int [] array , final int valueToFind , int lastIndex ) {
89
+ lastIndex = Math .min (array .length , lastIndex );
90
+ for (int i = 0 ; i <= lastIndex ; i ++ ) {
91
+ if (valueToFind == array [i ]) {
92
+ return true ;
93
+ }
94
+ }
95
+ return false ;
96
+ }
97
+
66
98
/**
67
99
* Returns a single min wise independent hash value
68
100
* using a linear transformation
@@ -136,13 +168,13 @@ public static long murmurHash(String string) {
136
168
137
169
if (left != 0 ) {
138
170
if (left >= 3 ) {
139
- hash ^= ( int ) data [dataLength - 3 ] << 16 ;
171
+ hash ^= data [dataLength - 3 ] << 16 ;
140
172
}
141
173
if (left >= 2 ) {
142
- hash ^= ( int ) data [dataLength - 2 ] << 8 ;
174
+ hash ^= data [dataLength - 2 ] << 8 ;
143
175
}
144
176
if (left >= 1 ) {
145
- hash ^= ( int ) data [dataLength - 1 ];
177
+ hash ^= data [dataLength - 1 ];
146
178
}
147
179
148
180
hash *= m ;
@@ -152,7 +184,7 @@ public static long murmurHash(String string) {
152
184
hash *= m ;
153
185
hash ^= hash >>> 15 ;
154
186
155
- return (long )( hash & 0x00000000ffffffffL );
187
+ return (hash & 0x00000000ffffffffL );
156
188
}
157
189
158
190
}
0 commit comments