Java Generic HashMap implementation: Object cannot be converted V - java

I'm trying to implement a generic HashMap, but for some reason the java compiler will not allow me to return the proper generic type.
Here is my HashMap code:
public class SimpleHashMap<K,V> {
private int tableSize;
private HashEntry[] table;
public SimpleHashMap(){
table = new HashEntry[tableSize];
for(int i = 0; i < table.length; i++){
table[i] = null;
}
}
public V put(K key, V value){
int keyIndex = getHashCode(key);
if(table[keyIndex] == null){
table[keyIndex] = new HashEntry<K, V>(key, value);
}
else{
table[keyIndex] = new HashEntry<K, V>(key, value, table[keyIndex]);
}
return value;
}
public V get(K key){
int keyIndex = getHashCode(key);
if(table[keyIndex] == null){
return null;
}
else{
HashEntry temp = table[keyIndex];
while(temp != null){
if(temp.key.equals(key)){
return temp.value;
}
temp = temp.next;
}
}
}
public int getHashCode(K key){
return key.hashCode() % tableSize;
}
}
Here is my HashEntry code:
public class HashEntry<K,V>{
public K key;
public V value;
public HashEntry next;
public HashEntry(K key, V value){
this(key, value, null);
}
public HashEntry(K key, V value, HashEntry next){
this.key = key;
this.value = value;
this.next = next;
}
}
The only error I get at compile time is:
error: incompatible types: Object cannot be converted to V
return temp.value;
^
where V is a type-variable:
V extends Object declared in class SimpleHashMap
I've tried explicitly casting it, but it still refuses to return a object of type V.

You need to declare your temp variable with type like this:
HashEntry<K,V> temp = table[keyIndex];
Your get method can be updated as follows:
public V get(K key){
int keyIndex = getHashCode(key);
if(table[keyIndex] == null){
return null;
}
else{
HashEntry<K,V> temp = table[keyIndex];
while(temp != null){
if(temp.key.equals(key)){
return temp.value;
}
temp = temp.next;
}
return temp.value;
}
}

HashEntry temp = table[keyIndex];
HashEntry is a generic type, but you are using it without type information.
If you want to use it like that, you have to make HashEntry a non-generic inner class and re-use the outer class type bounds.
public class HashEntry{ // has to be inside SimpleHashMap
public K key; // <-- type variables from
public V value; // <-- SimpleHashMap
public HashEntry next;
public HashEntry(K key, V value){
this(key, value, null);
}
public HashEntry(K key, V value, HashEntry next){
this.key = key;
this.value = value;
this.next = next;
}
}
The other possibility is to leave HashEntry as it is and change the line to
HashEntry<K, V> temp = table[keyIndex];

Related

How to add and compare keys of a generic hash table in Java?

I'm writing my own class for a generic hash table and trying to create an adding method as well as a method for comparing keys and returning true or false if they exist. So far my add method is not adding anything into my buckets, and my in my main, I cant pass any data type into my generic compare method without it asking me to define a new method with that type. Could anyone help point out the issues with my code as I'm trying to learn how to implement the data structure? Thank you.
My node and my table classes
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Objects;
class GenericHashNode <K, V> {
K key;
V value;
GenericHashNode<K, V> next;
public GenericHashNode (K key, V value) {
this.key = key;
this.value = value;
next = null;
}
public GenericHashNode() {
next = null;
}
}
public class GenericHashTable <K, V> {
private ArrayList<GenericHashNode<K, V> > hashArray;
private int tableSize;
public GenericHashTable(int tableSize)
{
hashArray = new ArrayList<>(tableSize);
this.tableSize = tableSize;
for (int i = 0; i < tableSize; i++) {
hashArray.add(new GenericHashNode());
}
}
private int getTableSize() {
return tableSize;
}
private int createHashCode(K key)
{
int h = key.hashCode();
h = h % getTableSize();
int hashCode = h < 0 ? h -= -h : h;
return hashCode;
}
public void add(K key) {
int hashIndex = createHashCode(key);
GenericHashNode head = hashArray.get(hashIndex);
GenericHashNode newNode = new GenericHashNode(key, key);
newNode.next = head.next;
head.next = newNode;
}
public boolean compare(K key) {
int hashIndex = createHashCode(key);
GenericHashNode current = new GenericHashNode();
current = hashArray.get(0);
Iterator<GenericHashNode<K, V>> iterate = hashArray.iterator();
while(iterate.hasNext()) {
if(current == null) {
current = current.next;
}
else {
if(current.key == key) {
return true;
}
else {
current = current.next;
}
}
}
return false;
}
}

Implementing isEmpty() for Linked Dictionary from scratch in Java

Currently, I'm working on a project in which I am implementing a Linked Dictionary interface from scratch. It was smooth sailing until I realized my code claims the entire dictionary is empty as soon as it sees a single null value.
public class LinkedDictionary<K, V> implements Dictionary<K, V> {
/** List node. */
private class Node {
K key;
V value;
Node next;
Node(K key, V value, Node next) {
this.key = key;
this.value = value;
this.next = next;
}
}
/** The first node in this dictionary, or null if this dictionary is empty. */
private Node front;
#Override
public void put(K key, V value) {
if(value == null) { // if a null value is given, the dictionary is empty
isEmpty();
return;
}
for (Node n = front; n != null; n = n.next) {
if (n.key.equals(key)) {
return;
}
}
front = new Node(key, value, front); // front node now contains new key and value
}
#Override
public V get(K key) {
if (key == null) // if a null key is given, null is returned
return null;
for (Node n = front; n != null; n = n.next) {
if (n.key.equals(key)) {
return n.value; // if they key is within the contents of the dictionary, return the corresponding value
}
}
return null; //if the key does not appear in the dictionary, null is returned.
}
#Override
public boolean isEmpty() {
return front == null;
}
}
I see my problem pretty clearly. In my "put" method, if the user tries to input a null value, the entire dictionary is marked as "empty."
I'm imagining this scenario:
Dictionary<Integer, String> d = new LinkedDictionary<>();
d.put(1, "one");
d.put(2, "two");
d.put(1, null);
As soon as my implementation reaches the third line in which the key 1 is set to null, it is going to set the entire dictionary to empty, despite the fact there is still a valid entry at key 2.
I've been wracking my brain over how to alter my code to allow for this sort of scenario, but I cannot figure it out. I've tried altering my isEmpty method, and I've even tried adding an additional method, but I just can't seem to figure out what to do here!
Any pointers or shoves in the right direction would be much appreciated!
public final class LinkedDictionary<K, V> {
private Node<K, V> head;
private Node<K, V> tail;
private int size;
public int getSize() {
return size;
}
public void put(K key, V value) {
Objects.requireNonNull(key, "Node.key");
Node<K, V> node = new Node<>(key, value);
remove(key);
if (isEmpty())
head = node;
else
tail.next = node;
size++;
tail = node;
}
public V remove(K key) {
Objects.requireNonNull(key, "Node.key");
if (isEmpty())
return null;
if (head.key.equals(key)) {
V value = head.value;
head = head.next;
tail = head == null ? null : tail;
size--;
return value;
}
Node<K, V> prv = head;
Node<K, V> it = head;
while (it != null) {
if (it.key.equals(key)) {
V value = it.value;
prv.next = it.next;
it.next = null;
size--;
return value;
}
prv = it;
it = it.next;
}
return null;
}
public V get(K key) {
Objects.requireNonNull(key, "Node.key");
Node<K, V> node = head;
while (node != null) {
if (node.key.equals(key))
return node.value;
node = node.next;
}
return null;
}
public boolean isEmpty() {
return head == null;
}
private static class Node<K, V> {
private final K key;
private final V value;
private Node<K, V> next;
public Node(K key, V value) {
this.key = key;
this.value = value;
}
}
}
I'm copy yours code excluding implementation and #Override, everything works fine
and d.isEmpty() give me a false as result

Why do I get "Pair cannot be cast to java.lang.Comparable" error?

I have this class:
public class Pair<V> implements Map.Entry<V,V> {
private V first;
private V second;
public Pair(){
}
public Pair (V first, V second){
this.first = first;
this.second = second;
}
#Override
public V getKey() {
return first;
}
#Override
public V getValue() {
return second;
}
#Override
public V setValue(V value) {
this.second = value;
return null;
}
#Override
public String toString() {
return "Pair{" +
"first=" + first +
", second=" + second +
'}';
}
}
Inside Program class I have this method:
public static <K,V extends Comparable> Pair<V> minmax(Map<K,V> map) {
List<V> values = new ArrayList<V>(map.values());
List<K> keys = new ArrayList<K>(map.keySet());
V min = (V)min(values);
V max = (V)max(values);
V minKey = (V)map.get(min);
V maxKey = (V)map.get(max);
Pair minPair = new Pair(minKey,min);
Pair maxPair = new Pair(maxKey,max);
return new Pair((V)minPair,(V)maxPair);
}
Here the row that calls the method above:
Pair minMax2 = minmax(mapGrades);
But on this row:
return new Pair((V)minPair,(V)maxPair);
I get this error:
Exception in thread "main" java.lang.ClassCastException: Pair cannot be cast to java.lang.Comparable
at Program.minmax(Program.java:35)
at Program.main(Program.java:14)
Any idea why I get the error above and how to fix it?
minPair and maxPair are of type Pair (well you could define them as Pair<V>). You can't cast them to V.
The type of new Pair(minPair,maxPair) can be Pair<Pair<V>>, not Pair<V>.
Besides, since your method should return a Pair<V>, it can return
Pair<V> minPair = new Pair<>(minKey,min);
or
Pair<V> maxPair = new Pair<>(maxKey,max);
but not new Pair(minPair,maxPair).

Can't find symbol - method (generic method)

I have two classes.
One is a Phrase class,
import java.util.List;
import java.util.ArrayList;
#SuppressWarnings("unchecked")
public class Phrase
{
List<String> papers = new ArrayList();
String name = "";
boolean multiple = false;
public Phrase(String name, List list)
{
this.name = name;
this.papers = list;
if(list.size() > 1)
{
multiple = true;
}
}
public Phrase(String name, String pName)
{
this.name = name;
this.papers.add(pName);
multiple = false;
}
public void addPaper(String paper)
{
papers.add(paper);
multiple = true;
}
public String getPhrase()
{
return name;
}
public List<String> getPapers()
{
return papers;
}
}
The Other is a KeyedLinkedList.
public class KeyedLinkedList<K,Phrase>
{
private KeyNode first;
private int size;
private class KeyNode
{
K key;
Phrase value;
KeyNode previous;
KeyNode next;
public KeyNode(K key, Phrase value, KeyNode previous, KeyNode next)
{
this.key = key;
this.value = value;
this.previous = previous;
this.next = next;
}
}
public int size()
{
return size;
}
public boolean put(K key, Phrase val)
{
if(isEmpty())
{
first = new KeyNode(key, val, null, null);
first.next = first;
first.previous = first;
size++;
return true;
}
KeyNode temp = first;
if(temp.key.equals(key))
{
//****ERROR LOCATION****//
temp.value.addPaper(val.getPapers().get(0));
//****ERROR LOCATION****//
if(temp.value.getPapers().size() < 3)
return false;
return true;
}
temp = temp.next;
while(temp != first)
{
if(temp.key.equals(key))
{
temp.value.addPaper(val.getPapers().get(0));
if(temp.value.getPapers().size() < 3)
return false;
return true;
}
temp = temp.next;
}
temp.previous.next = new KeyNode(key, val, temp.previous.next, first);
first.previous = temp.previous.next;
size++;
return true;
}
}
When I compile this I get the error: "Can't find symbol - method getPapers()"
I obviously have the getPapers() method in my Phrase class and val in the parameters is a Phrase object. I am wondering what I need to do to fix this problem. The error occurs half way through the put method.
public class KeyedLinkedList<K,Phrase>
// ^^^^^^
Here, you're declaring a type variable which has the same name as the Phrase class and shadows it. Any variables declared with the type Phrase refer to this type variable instead of the Phrase class.
Since I have no idea what your intent was, I can't really advise anything except to remove that.
public class KeyedLinkedList<K>
BTW, don't do this:
List<String> papers = new ArrayList();
// ^^^^^^^^^
It's called a raw type, it's bad, and there's no reason to use it. Do new ArrayList<String> instead.

Implementing a remove method in a java Hashmap?

So a hashmap is a hash-based implementation of a map structure in java. I've figured out how to get the hashmap put method to work, but I want to write a method that removes the key value pair, and I'm having trouble implementing it.
The only thing I can really understand right now is how to tell the function to stop in the event that the key is empty or doesn't exist.. I'd love any sort of help. An explanation as to how the method will work, or some basic pseudo-code examples would be much appreciated.
This is what I have in the delete method so far:
public void delete(K key) {
if (key == null) {
throw new IllegalArgumentException("Null Key!");
}
// Implement this method
}
If it helps, here is my completed Map Entry class:
public class MapEntry<K, V> {
MapEntry<K, V> next;
K key;
V value;
public MapEntry(K key, V value) {
this.setKey(key);
this.setValue(value);
}
public void setKey(K key) {
this.key = key;
}
public void setValue(V value) {
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public void setNext(MapEntry<K, V> next) {
this.next = next;
}
public MapEntry<K, V> getNext() {
return next;
}
}
Also, here's the entirety of my HashMap class if it helps.
public class HashMap<K, V> {
private int DEFAULT_CAPACITY = 10;
private MapEntry<K, V>[] Hash;
private int size;
public HashMap() {
Hash = new MapEntry[DEFAULT_CAPACITY];
}
public int getHashCode(K key) {
int bucketIndex = key.hashCode() % Hash.length;
return bucketIndex;
}
public V get(K key) {
if (key == null) {
throw new IllegalArgumentException("Null Key!");
}
MapEntry<K, V> entry = Hash[getHashCode(key)];
while (entry != null && !key.equals(entry.getKey()))
entry = entry.getNext();
if (entry != null)
return entry.getValue();
else
return null;
}
/**
*
* #param key
* #param value
* The put method works by associating the specified value with
* the given key in the map.
* If the key is already in the map,
* the old value is replaced with the new one.
*/
public void put(K key, V value) {
int keyBucket = hash(key);
MapEntry<K, V> temp = Hash[keyBucket];
while (temp != null) {
if ((temp.key == null && key == null)
|| (temp.key != null && temp.key.equals(key))) {
temp.value = value;
return;
}
temp = temp.next;
}
Hash[keyBucket] = new MapEntry<K, V>(key, value);
size++;
}
public void delete(K key) {
if (key == null) {
throw new IllegalArgumentException("Null Key!");
}
// Implement this method
}
public void print(){
//Bonus Method
}
private int hash(K key) {
if (key == null) {
return 0;
} else {
return Math.abs(key.hashCode() % this.Hash.length);
}
} }
Using the same logic that you do in get(), locate the correct bucket and, within that bucket, the correct MapEntry (let's call it e). Then simply remove e from the bucket—basically, this is removing a node from a single-linked list. If e is the first element in the bucket, set the corresponding element of Hash to e.next; otherwise set the next field of the element just before e to e.next. Note that you need one more variable (updated as you're finding e) to keep track of the previous entry in the bucket.
source code
public class MyInternalMap<K, V> implements Map<K, V> {
/**
* https://stackoverflow.com/questions/16266459/implementing-a-remove-method-in-a-java-hashmap
*/
private final int initialCapacity;
private MyMapEntry<K, V>[] mapEntries;
private int size;
public MyInternalMap() {
this(16);
}
public MyInternalMap(int initialCapacity) {
this.initialCapacity = initialCapacity;
mapEntries = new MyMapEntry[initialCapacity];
}
#Override
public int size() {
return size;
}
#Override
public boolean isEmpty() {
return size == 0;
}
#Override
public boolean containsKey(Object key) {
return get(key) != null;
}
#Override
public boolean containsValue(Object value) {
for (int i = 0; i < mapEntries.length; i++) {
MyMapEntry<K, V> mapEntry = mapEntries[i];
if (containsValue(value, mapEntry)) {
return true;
}
}
return false;
}
private boolean containsValue(Object value, MyMapEntry<K, V> mapEntry) {
if (mapEntry == null) {
return false;
}
if (value == mapEntry.getValue() || mapEntry.getValue().equals(value)) {
return true;
}
return containsValue(value, mapEntry.next);
}
#Override
public V get(Object key) {
if (key == null) {
return null;
}
MyMapEntry<K, V> entry = mapEntries[getHashCode(key)];
while (entry != null) {
if (key.equals(entry.key)) {
return entry.value;
}
entry = entry.next;
}
return null;
}
#Override
public V put(K key, V value) {
int keyBucket = getHashCode(key);
MyMapEntry<K, V> temp = mapEntries[keyBucket];
if (temp == null) {
//create new head node in this bucket
mapEntries[keyBucket] = new MyMapEntry<>(key, value);
size++;
return null;
}
while (temp != null) {
if ((temp.key == null && key == null)
|| (temp.key != null && temp.key.equals(key))) {
V returnValue = temp.value;
temp.value = value;
return returnValue;
}
temp = temp.next;
}
//create new node in this bucket
mapEntries[keyBucket].next = new MyMapEntry<>(key, value);
size++;
return null;
}
#Override
public V remove(Object key) {
/**
* Using the same logic that you do in get(), locate the correct bucket and, within that bucket, the correct MapEntry (let's call it e). Then simply remove e from the bucket—basically,
* this is removing a node from a single-linked list. If e is the first element in the bucket, set the corresponding element of Hash to e.next;
* otherwise set the next field of the element just before e to e.next. Note that you need one more variable (updated as you're finding e) to keep track of the previous entry in the bucket
*/
int keyBucket = getHashCode(key);
MyMapEntry<K, V> temp = mapEntries[keyBucket];
if (temp == null)
return null;
MyMapEntry<K, V> prev = temp;
while (temp != null) {
if (temp.key != null && temp.key.equals(key)) {
V valueReturn = temp.value;
if (prev == temp) { //first element?
mapEntries[keyBucket] = temp.next;
} else {
prev.next = temp.next;
}
size--;
return valueReturn;
}
prev = temp;
temp = temp.next;
}
return null;
}
#Override
public void putAll(Map<? extends K, ? extends V> m) {
//TODO impl
}
#Override
public void clear() {
mapEntries = new MyMapEntry[initialCapacity];
size = 0;
}
#Override
public Set<K> keySet() {
Set<K> resultKeys = new HashSet<>();
for (int i = 0; i < mapEntries.length; i++) {
MyMapEntry<K, V> mapEntry = mapEntries[i];
addKeySet(mapEntry, resultKeys);
}
return resultKeys;
}
private void addKeySet(MyMapEntry<K, V> mapEntry, Set<K> resultKeys) {
if (mapEntry != null) {
resultKeys.add(mapEntry.key);
addKeySet(mapEntry.next, resultKeys);
}
}
#Override
public Collection<V> values() {
Collection<V> resultValues = new ArrayList<>();
for (int i = 0; i < mapEntries.length; i++) {
MyMapEntry<K, V> mapEntry = mapEntries[i];
addValue(mapEntry, resultValues);
}
return resultValues;
}
private void addValue(MyMapEntry<K, V> mapEntry, Collection<V> resultValues) {
if (mapEntry != null) {
resultValues.add(mapEntry.value);
addValue(mapEntry.next, resultValues);
}
}
#Override
public Set<Entry<K, V>> entrySet() {
Set<Entry<K, V>> entrySetResult = new HashSet<>();
for (int i = 0; i < mapEntries.length; i++) {
MyMapEntry<K, V> mapEntry = mapEntries[i];
addEntrySet(mapEntry, entrySetResult);
}
return entrySetResult;
}
private void addEntrySet(MyMapEntry<K, V> mapEntry, Set<Entry<K, V>> entrySetResult) {
if (mapEntry != null) {
entrySetResult.add(mapEntry);
addEntrySet(mapEntry.next, entrySetResult);
}
}
private int getHashCode(Object key) {
if (key == null)
return 0;
int bucketIndex = Math.abs(key.hashCode()) % initialCapacity;
return bucketIndex;
}
class MyMapEntry<K, V> implements Map.Entry<K, V> {
private K key;
private V value;
private MyMapEntry<K, V> next;
public MyMapEntry(K key, V value) {
this.key = key;
this.value = value;
}
#Override
public K getKey() {
return key;
}
#Override
public V getValue() {
return value;
}
#Override
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
}
}
public class MyInternalMapTest {
#ParameterizedTest()
#MethodSource({"mapArgumentsProvider"})
public void mapTest(Map<Integer, String> map) {
assertNull(map.get(0));
assertNull(map.get(null));
assertNull(map.remove(0));
assertNull(map.remove(null));
assertNull(map.remove(1));
assertEquals(0, map.size());
assertNull(map.put(1, "1"));
assertEquals(1, map.size());
assertEquals("1", map.put(1, "2"));
assertEquals(1, map.size());
assertEquals("2", map.get(1));
assertEquals(1, map.size());
assertNull(map.put(2, "3"));
assertEquals(2, map.size());
assertEquals("2", map.remove(1));
assertEquals(1, map.size());
assertNull(map.remove(1));
assertEquals("3", map.remove(2));
assertEquals(0, map.size());
}
#ParameterizedTest()
#MethodSource({"mapArgumentsProvider"})
public void mapSameHashCodeTest(Map<Integer, String> map) {
assertNull(map.put(1, "1"));
assertEquals("1", map.get(1));
assertNull(map.put(17, "2"));
assertEquals("1", map.get(1));
assertEquals("2", map.get(17));
assertEquals("1", map.get(1));
assertTrue(map.containsValue("1"));
assertTrue(map.containsValue("2"));
assertFalse(map.containsValue("3"));
assertEquals(Arrays.asList("1", "2"), map.values().stream().sorted().collect(Collectors.toList()));
}
private static Stream<Arguments> mapArgumentsProvider() {
return Stream.of(
Arguments.of(new MyInternalMap<>()),
Arguments.of(new HashMap<>())
);
}
}

Categories

Resources