0

So I am building a hashtable from scratch using linear probing in Java with the following methods: put(int key, String value), get(int key), remove(int key) and size(). So I successfully implemented these methods, but I have a theoretical question. Let say for example, I do the following:

    var map = new HashMap(5);
    map.put(1, "a");
    map.put(3, "b");
    map.put(4, "c");
    map.put(8, "d");
    map.put(13, "e");
    map.remove(8);
    System.out.println(map);
    System.out.println(map.get(13));

My put method is working correctly and placing the key-value pairs according to Linear probing algo. Now my output is:

[null, 1=a, 13=e, 3=b, 4=c] null

So my question is, should my 'get' method theoretically fail (because of linear probing) to get the key-value pair 13=e because there of the remove method putting a null at index 0. Also if i don't use the remove, I'm successfully getting the 13=e pair.

1 Answers1

0

Your question is very reasonable and is one of the well-known problems with linear probing.

The problem is, if one of the items of your map is removed, then when you try to search for a value that in the process of searching you have to pass through the removed item, you won't be able to find it.

You can also ask it differently, what is the right way to search for a value, if you know that some values in the way might be null (removed items).

One solution would be to search until you've gone through the entire map, and if not found, return null. But that's a really bad solution because every time you use your get (or contains) method on a value that doesn't exist in the map, you'd have to go through the entire map (complexity of O(n)) which is not acceptable because HashMaps should implement those methods in at least averagely constant complexity (*O(1)).

So there are multiple solutions out there and you can research and read about them. I'll give you one solution that I know:

In your HashMap, save another array which will contain at every index, the maximum steps (or jumps) that were required in order to put a value in the map, where this index was the first you got to. Every time you put a new value in the map (using the put method) your method remembers the first index that you jumped to, and then if the total jumps you had to go through were bigger than the maximum steps at this index in your helper array, you update it.

Now, in your get() and contains() methods, when you make the first step, you read the maximum steps that are allowed from the helper array, and then you only have to jump this amount of steps until you can be sure that your value doesn't exist. That's instead of stopping when you get to a null key.