I am trying to implement the linear probing method. Right now, I have come until this point:
public class LinearProbing<Key, Value> {
private int size = 300001;
private Value[] value = (Value[]) new Object[size];
private Key[] key = (Key[]) new Object[size];
public Value put(Key thiskey, Value thisval) {
int hash = thiskey.hashCode();
for (int i = hash; key[i] != null; i = (i + 1) % size) {
if(key[i] == hash)
break;
key[i] = thiskey;
value[i] = thisval;
}
}
}
I am bit confused to proceed after this. Here are my doubts:
When I check the equality of this.key == hash, I get an error saying I can't compare Key and int.So I decided to return the Object from the hashcode method and compare it with the this.key[i].equals(hashObject). However doing this is against as hashcode method returns the int in the Javadoc and I want to keep it that way. How do I solve this?
Please let me know if I wasn't clear.
Related
So, I am in a Data Structures class and we are writing code and varying methods for Hashing. I am actually having trouble with the "get" method. The tests we have run fine until the last "key9" which is asserted to return null. The for loop for some reasons exits and the keyStartIndex is instantiated again. The method is not recursive so I have no idea why this is transpiring. Code is below. Any help is greatly appreciated.
Method I am trying to complete, that is having issues.
...
public String get(String key) {
//TODO : complete the method
int keyStartIndex = (int) hashFunction(key) % items.length;
for(int i = keyStartIndex; i < items.length; i++){
if(items[i].key == hashFunction(key)){
return items[i].item;
} else if(i == items.length-1){
i=0;
continue;
}
}
return null;
}
...
All prior code in this class that applies to this method
...
import java.util.Arrays;
import jdk.internal.org.objectweb.asm.tree.analysis.Value;
class DataItem {
long key;
String item;
public DataItem(long key, String item) {
this.key = key;
this.item = item;
}
#Override
public String toString() {
return String.format("{%s:%s}", key, item);
}
}
public class HashMap {
private int size = 0;
private static final int INITIAL_SIZE = 10;
private static final int DELETED_KEY = 0;
private DataItem[] items;
public HashMap() {
items = new DataItem[INITIAL_SIZE];
}
public int size() {
return size;
}
public long hashFunction(String key) {
long hashed = 0;
for(int i = 0; i < key.length(); i++){
hashed += key.charAt(i)*(Math.pow(27, i));
}
return hashed;
}
public void put(String key, String value) throws TableIsFullException {
if (size >= items.length-1){
throw new TableIsFullException();
} else {
DataItem input = new DataItem(hashFunction(key), value);
for(int i = ((int) input.key % items.length); i < items.length; i++){
if(items[i] != null){
continue;
}else if(i == items.length - 1 && items[i] != null){
i = 0;
continue;
} else {
items[i] = input;
size++;
break;
}
}
}
}
...
----------------------------------------------And the tests that are being ran, only the last one is failing again, with "key9". I have ran debugger and it says there is a nullPointerException. Again, with break points, for some reason it leaves the for loop and processes another key, key3 to be specific. I have no idea why this is happening.
#Test
public void testGet() throws TableIsFullException {
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
map.put("key4", "value4");
map.put("key5", "value5");
map.put("key6", "value6");
assertEquals("value3", map.get("key3"));
assertEquals(null, map.get("key9"));
}
Your put and get methods don't implement wraparound correctly. That means that when you get a couple of hash collisions towards the end of the table, things go haywire.
Secondly, you are not handling hash collisions correctly in either method. The contract for hash is that obj1.equals(obj2) implies hash1 == hash2, but not the other way around. That means that DataItem must record the original object as well as the hash. I will assume that you've added the appropriate field, and that DataItem now has three fields names key, hash and value.
Let's start with put:
The end condition is i >= items.length, so you either have an infinite loop if you wrap around, or you never wrap around.
Since you check items[i] != null first, i == items.length - 1 && items[i] != null can never be triggered, and so you never wrap around when the end of the table is full.
You never check if the existing item matches the new key.
One way to correct put is too treat items as a circular buffer. That means that you subtract off an offset modulo items.length:
int hash = hashFunction(key);
int offset = hash % items.length);
for(int i = 0; i < items.length; i++) {
int k = (i + offset) % items.length;
if(items[k] == null) {
items[k] = new DataItem(key, hash, value);
size++;
break;
}
if(items[k].hash == hash && items[k].key.equals(key)) {
items[k].value = value;
break;
}
}
You also need to fix your size check before throwing an exception. Checking size >= items.length - 1 will throw an exception when there is one free slot available. The correct condition is
if(size >= items.length) {
Your get method suffers from the same issue with wraparound as put. It also has the problem that you're checking for hash equality and not object equality when you retrieve an object.
int hash = hashFunction(key);
int offset = hash % items.length;
for(int i = 0; i < items.length; i++) {
int k = (i + offset) % items.length
if(items[k].hash == hash && items[k].key.equals(key)){
return items[i].value;
}
}
return null;
The check items[k].item.equals(key) is critical for resolving hash collisions correctly. Notice that it is only performed when the hashes match because of short circuiting.
Try to avoid recomputing values like hash inside a loop.
This whole scheme breaks down if you try to support a remove operation. If you notice, put will stop searching for matches once it finds an empty slot. This will break down if you can create empty slots before the matching object.
The NullPointerException that you see occurs because in the get() method you write
if(items[i].key == hashFunction(key))
Now if the specific key has not been added to the HashMap (and the items array is not yet full) the entry items[i] is still null and trying to access items[i].key gives the NullPointerException that you see.
The shortest test case for leads to your problem is:
#Test
public void keyNotFound() throws TableIsFullException {
assertEquals(null, map.get("key9"));
}
Besides that, carefully read the answer of "Mad Physicist" because it addresses other design flaws in your implementation (although not this one).
Post Details
In a data structures course, I was given Java source code for a "quadratic probing hash table" class and asked to implement a generic map (with get and put methods) and store the key/definition pairs in a hash table. I understand the material when reading the book but find it difficult to implement in a programming language (Java). I think part of the problem is understanding exactly what the question requires and part is deficiency in Java programming experience. I'm hoping to receive some suggestions for how I can approach problems like this and fill in whatever Java knowledge I'm missing.
Some questions I've had
What is the function of the hash table class in relation to the generic map I'm supposed to create? The hash table has several methods including get, insert, remove, rehash, etc... Is the purpose of the hash table to generate a hash value to use as a key in the map class? Are keys and definitions stored in the hash table or will they be stored in the map? What's the point of making a map if the hash table already does all of this?
Can someone help me understand how to approach problems like this? What are some references that might help me, either specifically with this question or with understanding how to effectively and methodically complete this type of exercise?
I appreciate whatever help I can get. I'm including code from the book to help illustrate the problem.
Quadratic Probing Hash Table Code From Textbook
public class QuadraticProbingHashTable<AnyType> {
public QuadraticProbingHashTable() {
this(DEFAULT_TABLE_SIZE);
}
public QuadraticProbingHashTable(int size) {
allocateArray(size);
doClear();
}
public boolean insert(AnyType x) {
int currentPos = findPos(x);
if(isActive(currentPos)) return false;
array[currentPos] = new HashEntry<>(x, true);
theSize++;
if(++occupied > array.length / 2) rehash();
return true;
}
private void rehash() {
HashEntry<AnyType>[] oldArray = array;
allocateArray(2 * oldArray.length);
occupied = 0;
theSize = 0;
for(HashEntry<AnyType> entry : oldArray)
if(entry != null && entry.isActive) insert(entry.element);
}
private int findPos(AnyType x) {
int offset = 1;
int currentPos = myhash(x);
while(array[currentPos] != null && !array[currentPos].element.equals(x)) {
currentPos += offset;
offset += 2;
if(currentPos >= array.length) currentPos -= array.length;
}
return currentPos;
}
public boolean remove(AnyType x) {
int currentPos = findPos(x);
if(isActive(currentPos)) {
array[currentPos].isActive = false;
theSize--;
return true;
} else return false;
}
public int size() {
return theSize;
}
public int capacity() {
return array.length;
}
public boolean contains(AnyType x) {
int currentPos = findPos(x);
return isActive(currentPos);
}
public AnyType get(AnyType x) {
int currentPos = findPos(x);
if(isActive(currentPos)) return array[currentPos].element;
else return null;
}
private boolean isActive(int currentPos) {
return array[currentPos] != null && array[currentPos].isActive;
}
public void makeEmpty() {
doClear( );
}
private void doClear() {
occupied = 0;
for(int i = 0; i < array.length; i++) array[i] = null;
}
private int myhash(AnyType x) {
int hashVal = x.hashCode();
hashVal %= array.length;
if(hashVal < 0) hashVal += array.length;
return hashVal;
}
private static class HashEntry<AnyType> {
public AnyType element;
public boolean isActive;
public HashEntry(AnyType e) {
this(e, true);
}
public HashEntry(AnyType e, boolean i) {
element = e;
isActive = i;
}
}
private static final int DEFAULT_TABLE_SIZE = 101;
private HashEntry<AnyType>[] array;
private int occupied;
private int theSize;
private void allocateArray(int arraySize) {
array = new HashEntry[nextPrime(arraySize)];
}
private static int nextPrime(int n) {
if(n % 2 == 0) n++;
for(; !isPrime(n); n += 2) ;
return n;
}
private static boolean isPrime( int n ) {
if(n == 2 || n == 3) return true;
if(n == 1 || n % 2 == 0) return false;
for(int i = 3; i * i <= n; i += 2)
if(n % i == 0) return false;
return true;
}
}
Map Skeleton From Textbook
class Map<KeyType,ValueType> {
public Map()
public void put(KeyType key, ValueType val)
public ValueType get(KeyType key)
public boolean isEmpty()
public void makeEmpty()
private QuadraticProbingHashTable<Entry<KeyType,ValueType>> items;
private static class Entry<KeyType,ValueType> {
KeyType key;
ValueType value;
}
}
Generally, what you're facing is a problem of implementing a given interface. The Map is the interface - the HashTable is a means of implementing it, the underlying data structure.
However, I understand your confusion as the definition of the HashTable that you were provided seems ill-suited for the job as it does not seem to have an option to use a custom key (instead always relying on the object's hash code for calculating the hash) nor does it have an option to have a custom HashEntry. As the question is specified, I would say the answer is "you can't". Generally, implementing a Map on a HashTable comes down to handling collisions - one approach, which is not very effective but usually works, is that whenever you find a collision (a case where you have differing keys but the same hashes), you rehash the entire table until the collision is no longer there. The more commonly adopted answer is having a multi-level hashtable, which basically recursively stores a hashtable (calculating a different hash function) on each level. Another method is having a hashtable of arrays - where the arrays themselves store lists of elements with the same hash - and rehashing if the number of collisions is too large. Unfortunately, neither of those solutions is directly implementable with the sample class that you were provided. Without further context, I cannot really say more, but it just seems like a badly designed exercise (this is coming from someone who does occasionally torture students with similar things).
An way of hacking this within your framework is creating a Pair type whose hashCode function just calculates key.hashCode(). This way, as a value you could store an array (and then use the array approach I mentioned above) or you could store a single element (and then use the rehash approach). In either solution, solving the collision handling is the most difficult element (you have to handle cases where the HashTable contains() your Pair, but the value part of the pair doesn't equals() the element that you want to insert.
Suppose I have this array:
double[][] Q = new double[n1][n2];
I could index the values of Q by using int indexes, such as Q[2][1]. But in my case, n1 is a byte[], not an int. I still know the possible values of n1 (e.g, all possible combinations of the array values). What collection should I use instead of an array?
HashMap<byte[], Double>[] Q = new HashMap[n2];
This was my solution, but I'm not sure it is adequate. To index, I can do
byte[] n1 = {1,0,6,1,4,2,5,1};
Q[1].get(n1);
Is there a better way to do this? Something that is more performant? I think having an array of HashMaps is not ideal, but can I add that int to my key? How?
As stated in the comments,
The problem with using an array as a hashmap key (aside from the fact that it's mutable) is that arrays don't calculate their hashcode based on their contents; so you couldn't actually look up a value in the map unless you have the actual key instance.
So how do I use an array as an indexing key? A stupid solution would be to always convert it to String before using it, but I'm sure there are better and proper solutions.
I think the best way to go for your problem is to define a complex key class, which basically consists of your byte[] and int, write reliable hashCode and equals-Methods for this class, and use it as a key to the HashMap.
This way, you can use the runtime and memory efficiency of a hashmap and encapsulate the complexity of the key in a separate class.
Code to illustrate:
public static class MyKey {
private int i;
private byte[] b;
private MyKey(int i, byte[] b) {
this.i = i;
this.b = b;
}
public static MyKey of(int i, byte ... b) {
return new MyKey(i, b);
}
#Override
public int hashCode() { // Autogenerated from eclipse
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(b);
result = prime * result + i;
return result;
}
#Override
public boolean equals(Object obj) { // Autogenerated from eclipse
if(this == obj)
return true;
if(obj == null)
return false;
if(getClass() != obj.getClass())
return false;
MyKey other = (MyKey) obj;
if(!Arrays.equals(b, other.b))
return false;
if(i != other.i)
return false;
return true;
}
}
public static void main(String[] args) {
HashMap<MyKey, Double> valueMap = new HashMap<>();
valueMap.put(MyKey.of(1, (byte)2, (byte)4, (byte)7), 0.1);
valueMap.put(MyKey.of(1, new byte[] { 3, 8, 14 }), 0.1);
}
I've been working on a Project Euler problem about coin combinations. I got the answer using recursion, but I wanted to try some dynamic programming so I built myself a Pair class and tried to use it as a key for a TreeMap. I was able to get it going but I kept getting the completely wrong solution.
I'm not sure what is going on. My friend suggested that perhaps something was happening with the Map trying to match the Pair references rather than values, but I tried overriding the .equals and modifying the compareTo method and it still doesn't work. (According to the docs I think TreeMap keys use equals method to match...
Here is my code. Hope someone can give it a quick browse and let me know why it doesn't work... if you uncomment the last return statement and get rid of all the map stuff you'll see my recursive only solution and that WORKS.
import java.util.Map;
import java.util.TreeMap;
public class Coins3 {
public static class Pair implements Comparable<Pair> {
Integer i1;
Integer i2;
Pair(Integer i1, Integer i2) {
this.i1 = i1;
this.i2 = i2;
}
#Override
public int compareTo(Pair arg0) {
// TODO Auto-generated method stub
if(this.equals(arg0)) return 0;
return this.i1 - arg0.i1;
}
public boolean equals(Pair arg0) {
if(this.i1.equals(arg0.i1) && this.i2.equals(arg0.i2)) return true;
return false;
}
}
static int[] coins = {1, 2, 5, 10, 20, 50, 100, 200};
static Map<Pair,Integer> memo = new TreeMap<Pair,Integer>();
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(nWays(coins.length,200));
}
public static int nWays(int index, int target) {
if(target == 0) return 1;
if(target < 0) return 0;
if(index <= 0 && target > 0) return 0;
// use the coin or not
int n1, n2;
Pair p1 = new Pair(index, target-coins[index-1]);
Pair p2 = new Pair(index-1, target);
if(memo.containsKey(p1)) {
n1 = memo.get(p1);
} else {
n1 = nWays(index,target-coins[index-1]);
memo.put(p1, n1);
}
if(memo.containsKey(p2)) {
n2 = memo.get(p2);
} else {
n2 = nWays(index-1,target);
memo.put(p2, n2);
}
return n1 + n2;
//return nWays(index-1,target) + nWays(index,target-coins[index-1]);
}
}
youve overridden equals() without overriding hashcode(), and used the class (class Pair) as a key in a map/set (your memo field).
classical beginner mistake - read this for why you should always override equals() and hashcode() together.
the short version: map always uses hashcode to "narrow down" the search key you provide, and only then uses equals() to match your key against the keys it finds "in the area". since you didnt override hashcode() your calls memo.containsKey(p1) and memo.containsKey(p2) might fail to locate the keys even if equals keys to p1/p2 exist
I have a function that accepts a HashMap<String, HashSet<Integer>>. Now I want to get a random value from the HashMap but I don't know how to do this. Could you give me a hint?
The output should consist of a tuple containing the String and an Integer value.
Knowing the size of the map, you could pick a random entry number, then iterate over the contents until you reach that entry. Example:
final Set<String> keys = allowedInput.keySet();
final int keyNumber = (int)(Math.random() * keys.size());
final Iterator<String> keyIterator = keys.iterator();
String randomKey = null;
for (int i = 0; i < keyNumber && keyIterator.hasNext(); i++) {
randomKey = keyIterator.next();
}
if (randomKey == null) {
// This should not happen unless the map was empty, or it was modified
// externally. Handle the potential error case accordingly.
}
final HashSet<Integer> value = allowedInput.get(randomKey);
// `value` now contains a random element from the `allowedInput` map.
If you want to retrieve a random Integer element from the resulting HashSet<Integer>, then you can adapt the same technique: simply pick a random element number based on the size of the set, and iterate over the contents until you find it.
If you want to repeatedly get random values, you could shuffle the set, and then go through it in order.
See Picking a random element from a set
I've created a generic solution that utilizes the answer of Mike and SecureRandom, and includes explicit null and bounds checking, as well as a quick return for singleton collections (not much to choose there).
public static <T> T getRandomElement(Collection<T> collection) {
if (collection == null || collection.isEmpty()) {
throw new IllegalArgumentException("Collection should not be null or empty");
}
if (collection.size() == 1) {
return collection.iterator().next();
}
// it would be beneficial to make this a field when used a lot
final Random random = new SecureRandom();
final int randomIndex = random.nextInt(collection.size());
// optimization for list instances, use optimized indexing
if (collection instanceof List) {
final List<T> list = (List<T>) collection;
return list.get(randomIndex);
}
int seen = 0;
for (T e : collection) {
if (seen++ == randomIndex) {
return e;
}
}
throw new IllegalStateException("Collection size was altered during operation");
}
Now you can simply retrieve a String and Integer by first selecting a key value from the key set, taking the value and choosing a random integer from that.
String key = getRandomElement(aMap.keySet());
Integer value = getRandomElement(aMap.get(key));
thx evry one for the help
i got i working now
this is the code i used
final Set<String> keys = allowedInput.keySet();
int keyNumber = (int)(random.nextInt(keys.size()));
final Iterator<String> keyIterator = keys.iterator();
String key = null;
for (int i = 0; i <= keyNumber; i++) {
key = keyIterator.next();
}
if (key == null) {
// handle empty map
}
HashSet<Integer> field = allowedInput.get(key);
final int fieldNumber = (int)(random.nextInt(field.size()));
int fieldID = 0;
int i = 0;
for(Object obj : field)
{
if (i == fieldNumber)
{
//fieldID = Integer.parseInt(obj.toString());
fieldID = (int)obj;
break;
}
i = i + 1;
}
// Start constructing the userinput
// Note: we need an instance of the UserInputSystem to create the UserInput instance!
UserInputSystem userInputSystem = new UserInputSystem();
UserInput input = userInputSystem.new UserInput(fieldID, key);
System.err.println("ai fieldID = "+fieldID+" key = "+key);