简体   繁体   中英

Implementing a put (or add) method for a Map/Associative Array Data Structure

I am given a Map Data Structure with the Generic Types (K,V) where the K represents the key, and the V represents the value.

Now I am asked to implement the classic put(K key, V value) method, which comes along with the collection. The method is pre-implemented, and overrides the one from an interface which is used:

@Override
    public void put(K key, V value) {
        for (int i = 0; i <= this.entries.length; i++) {
            if (this.entries[i] == null || this.entries[i].getKey().equals(key)) {
                this.entries[i] = new Entry<K, V>(key, value);
                return;
            } else {
                this.entries = GenericArrayHelper.copyArrayWithIncreasedSize(this.entries, (this.entries.length) * 2);
                /*  replace [...]
                this.entries[...] = new Entry<K, V>(key, value);
                 */
            }
        }
    }

With the exception of the part that's commented out, where I would need to replace the [...] with the correct position of the array. Namely:

If an Entry<K,V> at index i in the map is null, or the key of the entry at index i equals the key that was passed over, replace the entry with a new entry containing the key and value that are passed, and finish the method.

If such an Entry<K,V> cannot be found, the map (which is an array of the form entries<K,V>[ ]) which the method is called on, shall be copied in full and its array size shall be doubled (with the aiding method GenericArrayHelper.copyArrayWithIncreasedSize ). Successively, at the very first vacant slot of the copied and resized array , put in a new Entry with the passed key and value.

And this is where the confusion arose. I have tried to replace [...] with all kinds of indices, but have never gotten a satisfactory result.

When I try to put in these several entries, with putInside being a Map:

putInside.put("sizeInMB", 42);
putInside.put("version", 4);
putInside.put("yearOfRelease", 2015);

I shall get the following result, when printing ("stringified" with a separate toString method):

yearOfRelease : 2015
sizeInMB : 42
version : 4
yearOfRelease : 2015
sizeInMB : 42
version : 4

but when I, say, use the array index of entries.length-1 for [...], which is the closest I got to after hours of trying, and watch the debugger, it looks abysmal:

在此处输入图像描述

with the first three entries being correct, but the other three getting mashed up... and when I print the whole thing I merely get an output of the first tree entries, since the other three seem to be ignored completely (perhaps because the larger arrays in the for loop are merely defined in the loop itself?)

My question is: How do I define a suitable replacement for the index [...], or, maybe also for better understanding: Why on earth would we need to double the size of the array first? I have never implemented any Java Collection data structure before, and also haven't taken the data structures class at my uni yet... How do I get to a "doubled" output?

Any form of help would be really really appreciated!

EDIT: To make things clearer, here is the toString method:

public static void toString(Map<String, Integer> print) {
        for(String key : print.keysAsSet()){
                System.out.println(key + ": " + print.getValueFor(key));
        }
    }

with keysAsSet() returning a HashSet of the Map, which merely contains the keys, but not the values.

public Set<K> keysAsSet() {
        HashSet<K> current = new HashSet<>();
        for(Entry<K,V> entry : entries){
            if(entry != null) {
                current.add(entry.getKey());
            }
        }
        return current;
    }

The code doesn't match the description. To wit, you are resizing the array inside the loop , unless the very first element in entries is a hit (ie it's null or it equals the key).

You need to put the array resizing after the loop (plus fix the loop condition check):

@Override
public void put(K key, V value) {
    int oldLength = this.entries.length;
    for (int i = 0; i < oldLength; i++) {
        if (this.entries[i] == null || this.entries[i].getKey().equals(key)) {
            this.entries[i] = new Entry<K, V>(key, value);
            return;
        }
    }
    this.entries = GenericArrayHelper.copyArrayWithIncreasedSize(this.entries, oldLength * 2);
    this.entries[oldLength] = new Entry<K, V>(key, value);
}

… I assume you're aware that this is a very inefficient map implementation: each search and insertion take O ( n ) tries. In reality you'd either use a hash table or some sort of search tree to speed up insertion and lookup.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM