Foros del Web » Programación para mayores de 30 ;) » Java »

[SOLUCIONADO] Implementar TablaHash

Estas en el tema de Implementar TablaHash en el foro de Java en Foros del Web. Hola a todos, tengo una consulta que hacerles verán estoy viendo cómo implementar un HashMap y encontré una implementación bastante simplificada pero tengo problemas para ...

  #1 (permalink)  
Antiguo 17/04/2017, 22:14
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Implementar TablaHash

Hola a todos, tengo una consulta que hacerles verán estoy viendo cómo implementar un HashMap y encontré una implementación bastante simplificada pero tengo problemas para agregar las entradas hash ya que no me guarda bien los elementos:

Código Java:
Ver original
  1. private int findEntry(Object key){
  2.        // System.out.println("hashcode -> " + hash(key.hashCode()));
  3.         int hash = (key == null) ? 0 : hash(key.hashCode());        
  4.         int index =  hash & (table.length-1);
  5.        // System.out.println("pase -> " + index);
  6.         return index;
  7.     }
  8. static int hash(Object key) {
  9.         int h;
  10.         return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
  11.     }
  12. private HashEntry<K,V> getEntry(Object key){
  13.         HashEntry<K,V> e = table[findEntry(key)];
  14.         return (e != null && key.equals(e.key)) ? e : null;
  15.     }
  16. public V put(K key, V value) {
  17.         if(key == null){
  18.             return null;
  19.         }
  20.         Entry<K,V> e = this.getEntry(key);    
  21.         if(e != null){
  22.             return table[findEntry(key)].setValue(value);            
  23.         } else if(size == table.length){
  24.             table = Arrays.copyOf(table, table.length +1);
  25.         }
  26.         table[findEntry(key)] = new HashEntry(key,value);
  27.         size++;
  28.         return null;
  29.     }
  30. /*-----------------------------------------------------------*/    
  31.     protected class HashEntry<K,V> implements Entry<K,V> {
  32.         protected K key;
  33.         protected V value;
  34.         public HashEntry(K k, V v) {
  35.             key = k;
  36.             value = v;
  37.         }
  38.         @Override
  39.         public V getValue() {
  40.             return value;
  41.         }
  42.         @Override
  43.         public K getKey() {
  44.             return key;
  45.         }
  46.         @Override
  47.         public V setValue(V val) {
  48.             V oldValue = value;
  49.             value = val;
  50.             return oldValue;
  51.         }      
  52.         @Override
  53.         public int hashCode() {
  54.             return Objects.hashCode(key) ^ Objects.hashCode(value);
  55.         }        
  56.         @Override
  57.         public boolean equals(Object obj) {
  58.             if(obj instanceof HashEntry){
  59.                 HashEntry<K, V> ent = (HashEntry<K, V>) obj;
  60.                 return Objects.equals(key, ent.key) && Objects.equals(value, ent.value);
  61.             } else {
  62.                 return false;
  63.             }
  64.         }
  65.         @Override
  66.         public String toString() {
  67.             return "(key: " + key + ", value: " + value + ")";
  68.         }
  69.     }

Calculo que mi problema está en cómo tengo el hashCode y la función hash pero no le he encontrado la vuelta, por favor denme una mano con esto.

Espero sus respuestas y saludos.
  #2 (permalink)  
Antiguo 18/04/2017, 13:14
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Por favor, alguna ayuda con esto, comparto el código cuando lo tengamos terminado.
No es una estructura que está de cero sólo es arreglar detalles nada más.

Por favor, espero sus respuestas, Saludos.
  #3 (permalink)  
Antiguo 18/04/2017, 21:11
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Buenas a todos, estuve mirando el código que encontré y lo que me falla son los índices que me obtienen las funciones nunca me ponen en la posición 0 cuando se agregan por primera vez elementos de la tablahash:

Código Java:
Ver original
  1. public V put(K key, V value) {
  2.         if(key == null){
  3.             return null;
  4.         }
  5.         int index = getIndex(key); // acá no me obtiene el índice correcto me obtiene cualquier cosa
  6.         Pair<K, V> pair = table[index];
  7.         if (pair != null && (pair.key == key ||  pair.key.equals(key))) {
  8.             V oldValue = pair.value;
  9.             pair.value = value;
  10.             return oldValue;
  11.         }
  12.         setPair(key, value, index);        
  13.         return value;
  14.     }
  15. // funcion para obtener el hashCode de la clave
  16.     private int hashFunction(Object key) {  
  17.         if (key == null)
  18.             return 0;
  19.         String str = key.toString();
  20.         int summation = 0;
  21.         for (int i = 0; i < str.length(); i++)
  22.             summation += str.charAt(i);
  23.         return summation;
  24.     }
  25. // función para obtener el índice
  26.     private int getIndex(Object key) {
  27.         int hash = hashFunction(key);
  28.         return hash % capacity;
  29.     }
  30.     private void setPair(K key, V value, int index) {
  31.         Pair<K, V> e = table[index];
  32.         while (e != null) {
  33.             index++;
  34.             if (index >= capacity) {
  35.                 table = Arrays.copyOf(table, table.length +1);
  36.                 put(key,value);
  37.                 return;
  38.             }
  39.             e = table[index];
  40.         }
  41.         table[index] = new Pair<>(key, value);
  42.         size++;
  43.     }

El punto es que busqué en internet y no encontré una solución acorde a lo que quiero y lo peor es que usan de forma parecida para obtener los índices de los hash....

Por favor, alguna respuesta, la agradeceré.
  #4 (permalink)  
Antiguo 19/04/2017, 06:56
Avatar de Tipdar  
Fecha de Ingreso: octubre-2005
Ubicación: Aquí y allá.
Mensajes: 323
Antigüedad: 18 años, 6 meses
Puntos: 7
Respuesta: Implementar TablaHash

Hola detective_jd, me pregunto ¿qué sentido tiene implementar un hash map si ya Java cuenta con esa estructura de datos y muy bien implementada por cierto?
__________________
El último TipdaR
  #5 (permalink)  
Antiguo 19/04/2017, 18:43
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Hola Tipdar en realidad tiene mucho sentido si te pones a pensar, empezando que la estructuras hechas en Java (por la gente de Oracle) son un poco rebuscadas de entender si es que te pusiste a ver y trataste de entender el código, ya que siendo así te habrás dado por medio del HashMap se crean las HashSet, LinkedMashMap y LinkedHashSet, y sería bueno entender cómo funcionan bien los HashMap y cómo implementarlos......

Por otro lado estoy creando una estructura de datos para paginación de registros, de hecho tengo una creada para el uso de las listas que anda, y quiero hacer otra estructura de paginación pero con Maps ya que la de Set se logrará mediante Map.

Ahora si quieres ayudarme bienvenido sea, de lo contrario te pediré que reserves tu opinión. Gracias

Espero sus respuestas y Saludos.
  #6 (permalink)  
Antiguo 19/04/2017, 22:53
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Les cuento que encontrando una función hashCode me solucionó un poco el problema:

private int getIndex(Object key) {
return (key.hashCode() & 0x7FFFFFFF) % table.length;
}

pero me dio este resultado:

indice -> 1
indice -> 2
indice -> 3
indice -> 4

cuando tendría que hacer esto:

indice -> 0
indice -> 1
indice -> 2
indice -> 3

No sé si cambiar o agregar cosas en la Pair

Código Java:
Ver original
  1. class Pair<K,V> {
  2.         final K key;
  3.         V value;
  4.         Pair(K k, V v) {
  5.             value = v;
  6.             key = k;
  7.         }
  8.         public final K getKey() {
  9.             return key;
  10.         }
  11.         public final V getValue() {
  12.             return value;
  13.         }
  14.         @Override
  15.         public String toString() {
  16.             return getKey() + "=" + getValue();
  17.         }
  18.     }

o cambiar algo de los métodos para guardar la entrada en mi tablahash

Código Java:
Ver original
  1. public V put(K key, V value) {
  2.         if(key == null){
  3.             return null;
  4.         } else {
  5.             int index = getIndex(key);
  6.             System.out.println("indice -> "+ index);
  7.             Pair<K, V> pair = table[index];
  8.             if (pair != null && (pair.key == key ||  pair.key.equals(key))) {
  9.                 V oldValue = pair.value;
  10.                 pair.value = value;
  11.                 return oldValue;
  12.             }
  13.             setPair(key, value, index);        
  14.             return value;
  15.         }
  16.     }
  17. private int getIndex(Object key) {
  18.        return (key.hashCode() & 0x7FFFFFFF) % table.length;
  19.     }
  20.  
  21.     private void setPair(K key, V value, int index) {
  22.         Pair<K, V> e = table[index];
  23.         while (e != null) {
  24.             index++;
  25.             if (index >= capacity) {
  26.                 table = Arrays.copyOf(table, table.length +1);
  27.                 put(key,value);
  28.                 return;
  29.             }
  30.             e = table[index];
  31.         }
  32.         table[index] = new Pair<>(key, value);
  33.         size++;
  34.     }

Espero sus respuestas y Saludos.
  #7 (permalink)  
Antiguo 21/04/2017, 06:15
Avatar de Tipdar  
Fecha de Ingreso: octubre-2005
Ubicación: Aquí y allá.
Mensajes: 323
Antigüedad: 18 años, 6 meses
Puntos: 7
Respuesta: Implementar TablaHash

Siempre puedes redefinir métodos... cambiar el comportamiento, ya sabes.
__________________
El último TipdaR
  #8 (permalink)  
Antiguo 21/04/2017, 22:31
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Hola Tipdar verás la estructura está casi hecha tuve que hacer un truco medio chancho para continuar con el resto de las funcionalidades del HashMap casero:

Código Java:
Ver original
  1. private int getIndex(Object key) {
  2.        return (key.hashCode() & 0x7FFFFFFF) % table.length -1;
  3.     }

Tuve que restarle 1 para obtener el índice pero sé que eso no está bien, por otro lado cuando le pongo un tamaño por defecto y luego necesito agrandarlo me da este problema en la consola:

indice -> 0
indice -> 1
indice -> 2
indice -> -1
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1

Código Java:
Ver original
  1. public V put(K key, V value) {
  2.         if(key == null){
  3.             return null;
  4.         } else {
  5.             int index = getIndex(key);
  6.             System.out.println("indice -> "+ index);
  7.             Entry<K, V> pair = table[index];
  8.             if (pair != null && pair.getKey().equals(key)) {
  9.                 V oldValue = pair.getValue();
  10.                 pair.setValue(value);
  11.                 return oldValue;
  12.             }
  13.             setEntry(key, value, index);
  14.             return value;
  15.         }
  16.     }
  17. private void setEntry(K key, V value, int index) {
  18.         Entry<K, V> e = table[index];
  19.         while (e != null) {
  20.             index++;
  21.             if (index >= capacity) {
  22.                 table = Arrays.copyOf(table, table.length +1);
  23.                 put(key,value);
  24.                 return;
  25.             }
  26.             e = table[index];
  27.         }
  28.         table[index] = new Entry(key, value);
  29.         size++;
  30.     }

El resto de la estructura está hecha, ya pongo el código por si a alguien le interesa:

https://pastebin.com/QywGK6g8

Creo que quedaría esa parte del código para decir está listo.

Espero sus respuestas y Saludos
  #9 (permalink)  
Antiguo 23/04/2017, 08:41
 
Fecha de Ingreso: junio-2008
Ubicación: Seattle, USA
Mensajes: 733
Antigüedad: 15 años, 10 meses
Puntos: 61
Respuesta: Implementar TablaHash

Por que le restas 1?
La operacion modulo retorna valores entre 0 y el (numero-1), de modo que si le restas 1, te dara valores entre -1 y el numero-2, eso es lo que quieres? por que?
__________________
Visita mi perfil en LinkedIn
  #10 (permalink)  
Antiguo 23/04/2017, 11:59
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Hola CalgaryCorpus justamente eso es lo que no quiero, lo había hecho para continuar con el desarrollo del HashMap, pero ahora me veo en que necesito que me obtenga bien el índice sin la resta pero no me sale bien, no tengo un plan cómo para hacerlo andar.
Por otro lado también tengo problemas en caso de que por ejemplo: tengo dicho map de tamaño 4 por defecto pero me da error cuando quiero agregar en la posición 3 y no me deja.

Los que andan son put, getIndex, setEntry (provisorio de momento, xq cuando haga andar bien los otros 2, trataré de deshacerme de él).

Código Java:
Ver original
  1. @Override
  2.     public V put(K key, V value) {
  3.         if(key == null){
  4.             return null;
  5.         } else {
  6.             int index = getIndex(key);
  7.             System.out.println("indice -> "+ index);
  8.             Entry<K, V> pair = table[index];
  9.             if (pair != null && pair.getKey().equals(key)) {
  10.                 V oldValue = pair.getValue();
  11.                 pair.setValue(value);
  12.                 return oldValue;
  13.             }
  14.             setEntry(key, value, index);
  15.             return value;
  16.         }
  17.     }
  18.     private int getIndex(Object key) {
  19.        return (key.hashCode() & 0x7FFFFFFF) % table.length;
  20.     }
  21.  
  22.     private void setEntry(K key, V value, int index) {
  23.         Entry<K, V> e = table[index];
  24.         while (e != null) {
  25.             index++;
  26.             if (index >= capacity) {
  27.                 table = Arrays.copyOf(table, table.length +1);
  28.                 put(key,value);
  29.                 return;
  30.             }
  31.             e = table[index];
  32.         }
  33.         table[index] = new Entry(key, value);
  34.         size++;
  35.     }

Espero sus respuestas y Saludos.
  #11 (permalink)  
Antiguo 23/04/2017, 17:23
 
Fecha de Ingreso: junio-2008
Ubicación: Seattle, USA
Mensajes: 733
Antigüedad: 15 años, 10 meses
Puntos: 61
Respuesta: Implementar TablaHash

Ahora me parece mas razonable, dado que usas el modulo tamano de la tabla.
Que es lo que no funciona?

Como estas haciendo para probar que tu HashMap funciona?
Tienes uno o varios tests que ejercitas cada vez que cambias tu implementacion?
Si tienes tests, seria bueno incluirlos y decir algo como el test 1 no funciona, pero el 2, 3 y 4 si.
O poner nombres a los tests que digan que es lo que estan tratando de probar. Idealmente 1 sola cosa.
__________________
Visita mi perfil en LinkedIn
  #12 (permalink)  
Antiguo 23/04/2017, 19:56
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Gracias por responder CalgaryCorpus, mira estoy probando de esta manera la estructura:

Código Java:
Ver original
  1. package hashmapsimple;
  2. public class Cuerpo
  3. {
  4.     public static void main(String[] args) {
  5.         MyMap<Integer,String>col= new MyMap();
  6.         col.put(1, "Deborah");
  7.         col.put(2, "Tommy");
  8.         col.put(3, "Franco");
  9.         col.put(4, "Manuela");
  10.         col.put(null,"pepe");
  11.         /*
  12.         java.util.HashMap<Integer, String> m = new java.util.HashMap();
  13.         m.put(5, "Miguel");
  14.         m.put(6, "Denisse");        
  15.         col.putAll(m);
  16.         */
  17.         System.out.println(" ");
  18.         System.out.println("con containsKey: " + col.containsKey(1));
  19.         System.out.println("con containsKey: " + col.containsKey(7));
  20.         System.out.println(" ");
  21.         System.out.println("con get: " + col.get(1));
  22.         System.out.println("con get: " + col.get(7));
  23.         System.out.println(" ");
  24.         System.out.println("con containsValue: " + col.containsValue("Franco"));
  25.         System.out.println("con containsValue: " + col.containsValue("Rodrigo"));
  26.         System.out.println("con containsValue: " + col.containsValue(null));
  27.         //col.remove(2);
  28.         //col.remove(7);
  29.         //col.clear();
  30.         System.out.println(" ");
  31.         System.out.println("tamaño -> " + col.size());
  32.         System.out.println(" ");
  33.         System.out.println(" --valores-- ");
  34.         col.values().stream().forEach((s) -> {
  35.             System.out.println(s);
  36.         });
  37.         System.out.println(" ");
  38.         System.out.println(" --claves-- ");
  39.         col.keySet().stream().forEach((s) -> {
  40.             System.out.println(s);
  41.         });
  42.         System.out.println(" ");
  43.         System.out.println(" --entradas-- ");
  44.         col.entrySet().stream().forEach((e)->{
  45.             System.out.println("clave -> "+ e.getKey() +" valor -> "+e.getValue());
  46.         });        
  47.     }    
  48. }

sin la resta me da esto por consola:

sólo el key.hashCode(): 1
esta expresión (key.hashCode() & 0x7FFFFFFF); 1
indice -> 1

sólo el key.hashCode(): 2
esta expresión (key.hashCode() & 0x7FFFFFFF): 2
indice -> 2

sólo el key.hashCode(): 3
esta expresión (key.hashCode() & 0x7FFFFFFF): 3
indice -> 3

sólo el key.hashCode(): 4
esta expresión (key.hashCode() & 0x7FFFFFFF): 4
indice -> 0

para ver internamente el getIndex() hice esto:

Código Java:
Ver original
  1. private int getIndex(Object key) {
  2.         System.out.println("sólo el key.hashCode(): " + key.hashCode());
  3.         System.out.println("esta expresión (key.hashCode() & 0x7FFFFFFF): " + (key.hashCode() & 0x7FFFFFFF));
  4.         return (key.hashCode() & 0x7FFFFFFF) % table.length;
  5.     }

Prácticamente la función getIndex no funciona y ahí es dónde debo replantear el asunto.

Espero sus respuestas y saludos.
  #13 (permalink)  
Antiguo 23/04/2017, 22:20
 
Fecha de Ingreso: junio-2008
Ubicación: Seattle, USA
Mensajes: 733
Antigüedad: 15 años, 10 meses
Puntos: 61
Respuesta: Implementar TablaHash

Creo que la razon esta en como inicializas la tabla table, que no veo como se inicializa en el codigo que muestras. Si la estas inicializando de tamano X, hazlo, para comprobarlo, de tamano 10*x, y estimo que tu codigo se va a comportar bien. Si es asi, verifica que el tamano de la tabla crezca adecuadamente.
__________________
Visita mi perfil en LinkedIn
  #14 (permalink)  
Antiguo 23/04/2017, 23:09
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Gracias por responder CalgaryCorpus verás al "HashMap" casero lo inicializo de está forma:

Código Java:
Ver original
  1. public class MyMap<K, V> implements Map<K,V>{
  2.     private int capacity;
  3.     private int size;
  4.     private static final int DEFAULT_SIZE = 4;
  5.     private Entry<K,V>[] table;    
  6.     public MyMap() {
  7.         this(DEFAULT_SIZE);
  8.     }
  9.     public MyMap(int xcapacity) {
  10.         if(xcapacity <= 0){
  11.             throw new IllegalArgumentException("Capacidad no permitida: " + capacity);
  12.         } else {
  13.             this.capacity = xcapacity;        
  14.         }
  15.         this.clear();
  16.     }
  17.     public MyMap(Map<? extends K, ? extends V> m) {
  18.         this.putAll(m);
  19.     }
  20.     @Override
  21.     public void clear() {
  22.         table = new Entry[capacity];
  23.         size = 0;
  24.     }
  25.     .............................
  26. }

Con respecto al tamaño si crece o no tengo este dilema:

Código Java:
Ver original
  1. public V put(K key, V value) {
  2.         if(key == null){
  3.             return null;
  4.         } else {
  5.             int index = getIndex(key); // aqui me da los dolores de cabeza xq me termina haciendo relajo en la última posición como viste en el anterior mensaje
  6.             System.out.println("indice -> "+ index);
  7.             Entry<K, V> pair = table[index];
  8.             if (pair != null && pair.getKey().equals(key)) {
  9.                 V oldValue = pair.getValue();
  10.                 pair.setValue(value);
  11.                 return oldValue;
  12.             }
  13.             setEntry(key, value, index);
  14.             return value;
  15.         }
  16.     }

Espero sus respuestas y saludos.
  #15 (permalink)  
Antiguo 24/04/2017, 00:38
 
Fecha de Ingreso: junio-2008
Ubicación: Seattle, USA
Mensajes: 733
Antigüedad: 15 años, 10 meses
Puntos: 61
Respuesta: Implementar TablaHash

capacity lo inicializas y no lo actualizas cuando pides mas memoria. Eso esta mal, pues lo estas usando para controlar si tienes que pedir mas memoria o no.
Por que no pides memoria para 1 mas que capacity inicialmente, y si pides mas memoria luego duplicas cada vez en vez de aumentar en 1?
__________________
Visita mi perfil en LinkedIn
  #16 (permalink)  
Antiguo 24/04/2017, 22:47
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Hola CalgaryCorpus cambié un poquito el código para simplificarlo:

Código Java:
Ver original
  1. @Override
  2.     public V put(K key, V value) {
  3.         if(key == null){
  4.             return null;
  5.         } else {
  6.             int index = getIndex(key);
  7.             System.out.println("indice -> "+ index);
  8.             Entry<K, V> pair = table[index];
  9.             if (pair != null && pair.getKey().equals(key)) {
  10.                 V oldValue = pair.getValue();
  11.                 pair.setValue(value);
  12.                 return oldValue;
  13.             }
  14.             if(size == table.length){
  15.                 table = Arrays.copyOf(table, table.length +1);
  16.             }
  17.             table[index] = new Entry(key, value);
  18.             size++;
  19.             return value;
  20.         }
  21.     }    
  22.     private int getIndex(Object key) {
  23.         return (key.hashCode() & 0x7FFFFFFF) % table.length;
  24.     }

Estuve pensando en lo que me dijiste pero no le doy al clavo, te pongo la parte donde inicia, y todo xq no me encuentra el índice para posicionarlo en el array:

Código Java:
Ver original
  1. private int capacity;
  2.     private int size;
  3.     private static final int DEFAULT_SIZE = 4;
  4.     private Entry<K,V>[] table;    
  5.     public MyMap() {
  6.         this(DEFAULT_SIZE);
  7.     }
  8.     public MyMap(int xcapacity) {
  9.         if(xcapacity <= 0){
  10.             throw new IllegalArgumentException("Capacidad no permitida: " + capacity);
  11.         } else {
  12.             this.capacity = xcapacity;        
  13.         }
  14.         this.clear();
  15.     }
  16.     public MyMap(Map<? extends K, ? extends V> m) {
  17.         this.putAll(m);
  18.     }
  19.     @Override
  20.     public void clear() {
  21.         table = new Entry[capacity];
  22.         size = 0;
  23.     }

¿Cómo lo implementarías? ya que me queda sólo esto para terminar con la estructura.

Espero sus respuestas y Saludos.

Última edición por detective_jd; 24/04/2017 a las 23:17
  #17 (permalink)  
Antiguo 26/04/2017, 22:44
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Les cuento solucioné mi problema con lo de los índices, arreglando mi problema de esta forma:

crear una función para obtener el indice vacio para almacenar en el put

Código Java:
Ver original
  1. private int indexPut() {
  2.         for(int i= 0 ; i < table.length; i++){
  3.             if(table[i] == null){
  4.                  return i;
  5.             }
  6.         }
  7.         return -1;
  8.     }

Y para cuando quiero filtrar mi map para el get, containsKey y remove, hago otra función pasándole cómo parámetro la clave:

Código Java:
Ver original
  1. private int getIndex(Object key) {
  2.         for(int i= 0 ; i < table.length; i++){
  3.             if(table[i] != null && table[i].getKey() == key){
  4.                  return i;
  5.             }
  6.         }
  7.         return -1;
  8.     }

Aunque eso me hizo unos cuantos cambios, pero la estructura ya está en su 95% de funcionamiento salvo que no me anda el putAll:

Código Java:
Ver original
  1. @Override
  2.     public V put(K key, V value) {
  3.         if(key == null){
  4.             return null;
  5.         } else {
  6.             int index = indexPut();
  7.             Entry<K, V> pair = table[index];
  8.             if(size == table.length){
  9.                 table = Arrays.copyOf(table, table.length +1);
  10.             }
  11.             if (pair != null && pair.getKey().equals(key)) {
  12.                 V oldValue = pair.getValue();
  13.                 pair.setValue(value);
  14.                 return oldValue;
  15.             }            
  16.             table[index] = new Entry(key, value);
  17.             size++;
  18.             return value;
  19.         }
  20.     }
  21. @Override
  22.     public void putAll(Map<? extends K, ? extends V> m) {
  23.         if(m.size() > 0){
  24.             m.entrySet().forEach((e) -> {
  25.                 this.put(e.getKey(), e.getValue());
  26.             });
  27.         }
  28.     }

El problema se debe a que le pongo al inicializar un tamaño de 4 para probar si aumenta el almacenamiento del map en la función put pero no funciona.

Este error me da:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at hashmapsimple.MyMap.put(MyMap.java:38)
at hashmapsimple.MyMap.lambda$putAll$0(MyMap.java:135 )
at java.util.HashMap$EntrySet.forEach(HashMap.java:10 43)
at hashmapsimple.MyMap.putAll(MyMap.java:134)
at hashmapsimple.Cuerpo.main(Cuerpo.java:15)
/home/detectivejd/.cache/netbeans/8.2/executor-snippets/run.xml:53: Java returned: 1
BUILD FAILED (total time: 0 seconds)

Espero sus respuestas y Saludos.
  #18 (permalink)  
Antiguo 27/04/2017, 20:12
 
Fecha de Ingreso: junio-2008
Ubicación: Seattle, USA
Mensajes: 733
Antigüedad: 15 años, 10 meses
Puntos: 61
Respuesta: Implementar TablaHash

Haz las validaciones antes de las acciones.
__________________
Visita mi perfil en LinkedIn
  #19 (permalink)  
Antiguo 27/04/2017, 22:35
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Hey CalgaryCorpus gracias por responder, verás pude resolver mi problema, la función put me quedó de esta forma:

Código Java:
Ver original
  1. @Override
  2.     public V put(K key, V value) {
  3.         if(key == null){
  4.             return null;
  5.         } else {            
  6.             if(size == table.length){
  7.                 table = Arrays.copyOf(table, table.length +1);
  8.             }
  9.             int index = indexPut();
  10.             if (table[index] != null && table[index].getKey().equals(key)) {
  11.                 V oldValue = table[index].getValue();
  12.                 table[index].setValue(value);
  13.                 return oldValue;
  14.             }            
  15.             table[index] = new Entry(key, value);
  16.             size++;
  17.             return value;
  18.         }
  19.     }

Luego tuve otro problemilla más pero lo resolví que era el de las iteraciones:

Código Java:
Ver original
  1. @SuppressWarnings("empty-statement")
  2.         public Entry<K,V> nextEntry() {
  3.             currEntry = nextEntry;                            
  4.             index++;
  5.             // tuve que hacer este if para que no me diera error por el tema de los índices
  6.             if (index != size && table[index] != null) {
  7.                 nextEntry = table[index];              
  8.             } else {
  9.                 nextEntry = null;
  10.                 for (;index < table.length; index++){
  11.                     if (table[index] != null){
  12.                         nextEntry = table[index];
  13.                     }
  14.                 }
  15.             }
  16.             return currEntry;
  17.         }      
  18.     }

Quería saber tu opinión porque en así están rebuscados tanto el put como el de las iteraciones.
Y de paso preguntarte: ¿si publico mi código completo con comentarios lo mirarías? es que quiero tener una opinión objetiva de la estructura y también pondría tu nombre cómo autor del código además del mío jeje....

Espero sus respuestas y Saludos.

PD1: Porque luego de esto quiero ver si con este código puedo hacer bien HashSet (de la misma forma que Oracle, xq ellos trabajan internamente con el HashMap para las funciones y los métodos de HashSet).

PD2: Estaba trasnochado cuando escribí el mensaje anterior.
  #20 (permalink)  
Antiguo 30/04/2017, 22:23
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Buenas a todos, quería poner el código completo aquí:

Implementación de HashMap con comentarios de cada cosa hecha

https://pastebin.com/LnmEN8jJ

En este otro link están las pruebas hechas que hice verificando sí anda o no:

https://pastebin.com/KVyP3yd3

Me gustaría saber sus opiniones, ya que las cuales serán muy importantes para lo que vaya a hacer después.

Espero sus respuestas y Saludos.
  #21 (permalink)  
Antiguo 01/05/2017, 08:11
 
Fecha de Ingreso: junio-2008
Ubicación: Seattle, USA
Mensajes: 733
Antigüedad: 15 años, 10 meses
Puntos: 61
Respuesta: Implementar TablaHash

Felicitaciones por la publicacion del codigo.
Has pensado en usar github o similar?
No creo que el foro sea la mejor manera de iterar sobre el, en realidad, pues es muy extenso y tal vez no sea de mucha utilidad algo como pastebin una vez que recibas comentarios y decidas cambiarlo.

Ejemplo:
- Elimina de los comentarios que cada metodo empiece con "metodo que ..." o "funcion que ..", es superfluo decirlo.
- Elimina en genral todos los comentarios superfluos o que no aporten a comprender el codigo. Ejemplo de esto es poner como comentario "constructor" al constructor por default.
- Por que tu constructor no pide memoria para la tabla?
- Por que al usar la capacidad de la tabla solo pides memoria para 1 elemento mas. No es razonable aumentar al doble? o aumentar tanto como se pidio al inicio en el constructor?
- Hay errores de tipeo en los comentarios, por ejemplo dice "incremenatamos", "qye"
- Como esta construido el metodo getIndex solo retorna un valor -1 si es que encuentra el objeto al interior, de modo que es superfluo preguntar una vez que usaste ese metodo si es que el objeto es efectivamente el que buscabas, si esto no fuera asi, tu metodo getIndex estaria mal construido.
- capacity no lo usas, eliminalo (o usalo, actualizalo)
- Si existiera una manera magica de que dado un objeto con una clave cualquiera te dijera exactamente donde esta o donde deberia ir, sin tener que recorrer el arreglo, y fuera super rapida, la usarias? Eso es lo que esta detras de hashCode que apareces menospreciando al inicio en el comentario inicial. Si tu arreglo creciera a varios miles de datos la funcion magica se hace mas y mas atractiva.
- getIndex podria terminar antes la iteracion al encontrar el primer null
- al borrar, puesto que no hay orden interno, por que no mueves solo el ultimo elemento a la posicion del que borras, en vez de mover todos 1 lugar?
- Sugiero hacer varias pruebas pequenas en vez de hacer 1 sola gran prueba. Cada prueba es 1 metodo, en cada prueba creas un hashmap, agregas entradas y pruebas que un cierto metodo del hashmap funciono. Cada prueba ejercita 1 cosa, y el resto de las pruebas asumen que lo que ya probaste no hay que probarlo de nuevo. Puedes probar los distintos constructores que provees, pues ahora estas probando solo 1, que pasa cuando usas un tamano explicito?

Una vez que tengas estos comentarios considerados, volveras a publicar en el foro un link a otro sitio? Eso es lo que me parece que no esta bien, pues el foro pierde su valor, no?
__________________
Visita mi perfil en LinkedIn
  #22 (permalink)  
Antiguo 01/05/2017, 22:41
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Hola CalgaryCorpus muchísimas gracias por responder, no sabés cómo me ayudó tu opinión:

Cita:
Has pensado en usar github o similar?
No creo que el foro sea la mejor manera de iterar sobre el, en realidad, pues es muy extenso y tal vez no sea de mucha utilidad algo como pastebin una vez que recibas comentarios y decidas cambiarlo.
La verdad me había olvidado de github, bueno como eran 2 archivos pensé que no pasaría nada, pero con lo de las pruebas si, lo haré en github la próxima vez.

Cita:
- Elimina de los comentarios que cada metodo empiece con "metodo que ..." o "funcion que ..", es superfluo decirlo.
Ya lo hice

Cita:
- Elimina en genral todos los comentarios superfluos o que no aporten a comprender el codigo. Ejemplo de esto es poner como comentario "constructor" al constructor por default.
Ya lo hice

Cita:
- Por que tu constructor no pide memoria para la tabla?
¿A que te refieres? Puede que haya olvidado el concepto y la idea.

Cita:
- Por que al usar la capacidad de la tabla solo pides memoria para 1 elemento mas. No es razonable aumentar al doble? o aumentar tanto como se pidio al inicio en el constructor?
Me aseguré de que aumenté el doble.

Cita:
- Hay errores de tipeo en los comentarios, por ejemplo dice "incremenatamos", "qye"
Me deshice de eso

Cita:
- capacity no lo usas, eliminalo (o usalo, actualizalo)
Eliminé a capacity por relleno.

Cita:
- al borrar, puesto que no hay orden interno, por que no mueves solo el ultimo elemento a la posicion del que borras, en vez de mover todos 1 lugar?
Hice lo que me dijiste y funcionó, además en las tablas hash el órden es lo que menos importa.

Cita:
- Sugiero hacer varias pruebas pequenas en vez de hacer 1 sola gran prueba. Cada prueba es 1 metodo, en cada prueba creas un hashmap, agregas entradas y pruebas que un cierto metodo del hashmap funciono. Cada prueba ejercita 1 cosa, y el resto de las pruebas asumen que lo que ya probaste no hay que probarlo de nuevo. Puedes probar los distintos constructores que provees, pues ahora estas probando solo 1, que pasa cuando usas un tamano explicito?
Hice todas las pruebas y anda bien, aunque tuve que hacer algunas modificaciones.

Eso es lo que pude hacer
-----------------------------------------------------------------------------------------------------

Cita:
Como esta construido el metodo getIndex solo retorna un valor -1 si es que encuentra el objeto al interior, de modo que es superfluo preguntar una vez que usaste ese metodo si es que el objeto es efectivamente el que buscabas, si esto no fuera asi, tu metodo getIndex estaria mal construido.
Cita:
- Si existiera una manera magica de que dado un objeto con una clave cualquiera te dijera exactamente donde esta o donde deberia ir, sin tener que recorrer el arreglo, y fuera super rapida, la usarias? Eso es lo que esta detras de hashCode que apareces menospreciando al inicio en el comentario inicial. Si tu arreglo creciera a varios miles de datos la funcion magica se hace mas y mas atractiva.
Cita:
- getIndex podria terminar antes la iteracion al encontrar el primer null
No es que menosprecie al HashCode para nada, el problema es que intenté e intenté implementarlo pero no dí al clavo....
Busqué algo llamado búsqueda por transformación de claves pero no hay una implementación y una de esas me manda sólo al principio.

Código Java:
Ver original
  1. public int hash(Object key){
  2.         return key.hashCode() % table.length;
  3.     }

que vimos que no funcionó, sé que logro eso y logro un mini calco de la implementación de Oracle.

Espero sus respuestas y saludos.
  #23 (permalink)  
Antiguo 02/05/2017, 20:19
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Hola CalgaryCorpus y a todos, estuve mirando lo de hashCode y encontré esto:

Código Java:
Ver original
  1. private int getIndex(Object key) {
  2.         int ret = key.hashCode() % table.length;
  3.         if(ret < 0) {
  4.             ret += table.length;
  5.         }
  6.         return ret;
  7.     }

El cual andar anda, pero cuando quiero agregar más de 4 elementos me hace esto por consola:

---PROBANDO MAP2---
tamaño -> 7

--valores--
John
Paula
Andrea

--claves--
4
1
6

--entradas--
clave -> 4 valor -> John
clave -> 1 valor -> Paula
clave -> 6 valor -> Andrea

cuando en el map2 agregue esto:

Código Java:
Ver original
  1. MyMap<Integer,String>m2= new MyMap(2);
  2.         m2.put(1, "Paula");
  3.         m2.put(2, "Pedro");
  4.         m2.put(3, "Fabio");
  5.         m2.put(4, "John");
  6.         m2.put(5, "Manuela");
  7.         m2.put(6, "Andrea");
  8.         m2.put(7, "Luisa");

Por otro lado hice un pequeño cambio a addEntry xq cómo estaba haciendo de que duplica cuando la cantidad actual es igual al largo es ineficiente debido a la lentitud del mismo, y tuve que cambiar la condición:

Código Java:
Ver original
  1. @Override
  2.     public V put(K key, V value) {
  3.         if(key != null){
  4.             int index = this.getIndex(key);
  5.             if (table[index]!= null && table[index].getKey().equals(key)) {
  6.                 V oldValue = table[index].getValue();
  7.                 table[index].setValue(value);
  8.                 return oldValue;
  9.             }  
  10.             this.addEntry(key, value, index);
  11.             return value;
  12.         }
  13.         return null;
  14.     }
  15.     private void addEntry(K key, V value, int index){
  16.         if(size >= table.length * 3/4){
  17.             table = Arrays.copyOf(table, table.length * 2);
  18.         }
  19.         table[index] = new Entry(key, value);
  20.         size++;
  21.     }

En esta página lo explica mejor: http://www.toves.org/books/data/ch06-hash/

A mi getIndex que tiene el código del hashCode le falta algo pero no sé que, no sé que pueden decir.

Espero sus respuestas y saludos.
  #24 (permalink)  
Antiguo 02/05/2017, 20:46
 
Fecha de Ingreso: junio-2008
Ubicación: Seattle, USA
Mensajes: 733
Antigüedad: 15 años, 10 meses
Puntos: 61
Respuesta: Implementar TablaHash

La tabla está siendo recreada, usar el hashcode y la operación de modulo funciona bien si la tabla no cambia de tamaño, para comprobarlo, inicializa tu hashmap con un tamaño mayor que el número de elementos insertados.

Si vas a modificar el tamaño, vas a afectar tu cálculo del indíce, tal como lo tienes, o tienes en cuenta eso o bien cuentas con una estrategia para resolver colisiones.
__________________
Visita mi perfil en LinkedIn
  #25 (permalink)  
Antiguo 02/05/2017, 22:25
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Hola CalgaryCorpus acabo de probar inicializando con 16 o 24 y me hace esto:

1
2
3
4
5
6
7

---PROBANDO MAP2---
tamaño -> 7

--valores--

--claves--

--entradas--

no me da indice 0 y por consecuente tampoco me lista nada,
Estuve mirando en algunos sitios sobre resolución de colisiones y hasta lo que me pueda servir más puede ser esto:

https://www.infor.uva.es/~cvaca/asigs/doceda/tema5.pdf

Pero mañana lo probaré, aunque me gustaría tu opinión al respecto viendo visto mi código y estos leves cambios respecto que publiqué.

Espero sus respuestas y Saludos.
  #26 (permalink)  
Antiguo 02/05/2017, 23:00
 
Fecha de Ingreso: junio-2008
Ubicación: Seattle, USA
Mensajes: 733
Antigüedad: 15 años, 10 meses
Puntos: 61
Respuesta: Implementar TablaHash

Si usas el hashCode tienes que dejar de usar el acceso secuencial de los datos, no te va a funcionar tampoco el borrado tal como lo tienes, pues tambien supone datos consecutivos, pero sera rapido de accesar los datos que ya estan, si conoces la key.
__________________
Visita mi perfil en LinkedIn
  #27 (permalink)  
Antiguo 03/05/2017, 23:04
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Hola CalgaryCorpus intenté hacer esto para el tema de las colisiones:

Código Java:
Ver original
  1. private int getIndex(Object key) {
  2.         int ret = key.hashCode() % table.length;
  3.         if(ret < 0) {
  4.             ret += table.length;
  5.         }
  6.         System.out.println(ret);
  7.         return ret;
  8.     }
  9. private void addEntry(K key, V value){
  10.         if(size >= table.length * 3/4){
  11.             Entry<K,V>[] tmp = table;
  12.             size = 0;
  13.             cap = 2 * cap;
  14.             table = new Entry[cap];
  15.             for(int i = 0; i < cap; i++){
  16.                 table[i] = null;
  17.             }
  18.             for (Entry<K, V> e : tmp) {    
  19.                 if(e != null){
  20.                     put(e.getKey(),e.getValue());
  21.                 }
  22.             } //table = Arrays.copyOf(table, table.length * 2);
  23.         }
  24.         int index = getIndex(key);
  25.         table[index] = new Entry(key, value);
  26.         size++;
  27.     }

Pero me terminó haciendo esto:

run:
1
1
2
2
3
3
0
1
1
2
2
3
3
4

---PROBANDO MAP1---
tamaño -> 4

--valores--

--claves--

--entradas--

¿Que estrategia me dirías para el tema de las colisiones?

Espero sus respuestas y Saludos.
  #28 (permalink)  
Antiguo 04/05/2017, 05:45
 
Fecha de Ingreso: junio-2008
Ubicación: Seattle, USA
Mensajes: 733
Antigüedad: 15 años, 10 meses
Puntos: 61
Respuesta: Implementar TablaHash

Asumo que no has cambiado el recorrido que haces para imprimir el contenido del hashmap. Hazlo. Sino, seguirás viendo contenido parcial o nada.
No estás haciendo nada por las colisiones, revisa los links que tú mismo dejaste aquí para que veas opciones.
Recuerda que si tu tabla crece, invalidas lo que ya tienes en el map.
__________________
Visita mi perfil en LinkedIn
  #29 (permalink)  
Antiguo 04/05/2017, 21:20
Avatar de detective_jd  
Fecha de Ingreso: abril-2011
Ubicación: Salto
Mensajes: 437
Antigüedad: 13 años
Puntos: 6
Respuesta: Implementar TablaHash

Hola CalgaryCorpus con respecto a los recorridos, estuve mirando y no pude con esto, pero también dime cambiar el recorrido para imprimir debo tener en cuenta el hashCode ¿verdad? en este caso sería getIndex, xq excepto eso no se me ocurre nada:

Código Java:
Ver original
  1. private abstract class HashIterator<E> implements Iterator<E> {
  2.         private int index = 0;
  3.         private Entry<K,V> currEntry = null;
  4.         private Entry<K,V> nextEntry = null;
  5.         /**
  6.          * Construye una nueva iteración hash
  7.          */
  8.         @SuppressWarnings("empty-statement")
  9.         HashIterator() {
  10.             if (table[index] != null){
  11.                 nextEntry = table[index];
  12.             }            
  13.         }
  14.         /**
  15.          * Verifica si hay una siguiente entrada
  16.          *
  17.          * @return boolean -> verdadero o falso
  18.          */
  19.         @Override
  20.         public boolean hasNext() {
  21.             return nextEntry != null;
  22.         }
  23.         /**
  24.          * Obtiene la entrada próxima, y también es una función
  25.          * sobreexplotada para los recorridos ;)
  26.          *
  27.          * @return Entry<K,V> -> entrada clave/valor
  28.          */
  29.         @SuppressWarnings("empty-statement")
  30.         public Entry<K,V> nextEntry() {
  31.             currEntry = nextEntry;
  32.             index++;
  33.             if (index < size && table[index] != null) {
  34.                 nextEntry = table[index];              
  35.             } else {
  36.                 nextEntry = null;
  37.                 for (;index < size; index++){
  38.                     if (table[index] != null){
  39.                         nextEntry = table[index];
  40.                     }
  41.                 }
  42.             }
  43.             return currEntry;
  44.         }      
  45.     }

Porque si no resuelvo esto, no podré continuar.

Espero sus respuestas y saludos.
  #30 (permalink)  
Antiguo 04/05/2017, 23:08
 
Fecha de Ingreso: junio-2008
Ubicación: Seattle, USA
Mensajes: 733
Antigüedad: 15 años, 10 meses
Puntos: 61
Respuesta: Implementar TablaHash

Si el hashcode te indica posiciones disjuntas o separadas, especialmente si no parten del inicio del arreglo, no puedes hacer un recorrido que no considere eso.
Considera que la tabla ha sido llenada de manera disjunta y no necesariamente partiendo de la primera posicion. Miro tu codigo y es esto lo que asumes y por eso no funciona lo que has hecho. Obtener la siguiente posicion ocupada tambien tendra la misma suposicion (disjuntas) y tendra el mismo problema si supones que los datos estan uno despues del otro.
__________________
Visita mi perfil en LinkedIn

Etiquetas: entrada, implementar
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 06:00.