Problema con mapas

Iniciado por Orubatosu, 19 Diciembre 2014, 16:28 PM

0 Miembros y 1 Visitante están viendo este tema.

Orubatosu

Tengo un curioso problema que me esta mareando un poco, os explico:



int main(){
   string entrada;
   map <int, bool> A;
   map <int, bool> B;
   getline (cin, entrada);
   cout << entrada << endl;
   A = separa (entrada);
   while (getline (cin, entrada)){
       B = separa (entrada);
       map<int, bool>::iterator it = A.begin();
       for (; it != A.end(); it++){
           map<int, bool>::iterator itb = B.find(it->first);
           if (itb == B.end()){
               A.erase(it->first);
               map<int, bool>::iterator it = A.begin();
           }
       }
       muestra (A);
   }
}



Omito las funciones y cabeceras, se que funcionan y no me dan problemas, y aclaro un poco este follón de código.

Lo que hago, es capturar secuencias de enteros y filtrar solo los que aparecen en todas las líneas. Mi idea es capturar una linea y meterla en un mapa (Mapa A), las siguientes en el mapa "B".

Luego, itero el mapa "A" y compruebo si la llave del iterador existe en el mapa "B", y en caso de que no sea así, borro de A esa clave.

El caso es que el programa, tal y como está "revienta". Solo puedo asumir que tengo un iterador "loco" corriendo por ahi, pero no acabo de ver cual, porque veamos:

Tengo un iterador "it" que va a recorrer los valores del mapa A, y lo ubico en su primera casilla. Luego, compruebo con el iterador ITB si el valor de la llave de ese iterador existe en "B", si el valor devuelto es "B.end" entonces es que no está, por lo que borro ese contenido en "A".
Soy consciente desde luego, que desde el momento en que efectuo una operación de borrado, ese iterador deja de ser valido, por lo que lo devuelvo a su punto inicial, pero vamos... no se porque "explota"

Estoy pensando obviamente en no borrar nada, y usar el valor asociado a la clave (que es booleano) para marcarlo, y ya os diré como va la cosa, pero claro, el tema es que si quisiera borrar datos, me veo ante un código que falla, y no tengo claro porque.

A ver si alguien ve donde estoy metiendo la gamba

Por cierto, si hago eso que os he comentado, el programa funciona... os pongo el código entero por si alguien quiere aclararse un poco mas



#include <iostream>
#include <sstream>
#include <map>
using namespace std;

map <int, bool> separa (string& s){
   istringstream S (s);
   map<int, bool> ret;
   int n;
   while (S >> n){
       ret[n] = false;
   }
   return ret;
}

void muestra (const map<int, bool>& m){
   map<int, bool>::const_iterator itm = m.begin();
   for (; itm != m.end(); itm++){
       if (itm->second == false) cout << itm->first << ' ';
   }
   cout << endl;
}

int main(){
   string entrada;
   map <int, bool> A;
   map <int, bool> B;
   getline (cin, entrada);
   cout << entrada << endl;
   A = separa (entrada);
   while (getline (cin, entrada)){
       B = separa (entrada);
       map<int, bool>::iterator it = A.begin();
       for (; it != A.end(); it++){
           map<int, bool>::iterator itb = B.find(it->first);
           if (itb == B.end()){
               it->second = true;
           }
       }
       muestra (A);
   }
}


Claro, el programa ahora va, pero sigo sin saber porque la versión anterior que borraba los elementos no repetidos no lo hace, y preferiría saber porque es eso, antes que pensar "buenooooo ahora funciona, no me preocupo mas"
"When People called me freak, i close my eyes and laughed, because they are blinded to happiness"
Hideto Matsumoto 1964-1998

avesudra

#1
Hola Orubatosu, sin ver bien donde revienta el programa, solo veo que estas declarando un iterador nuevo y no modificando el existente al volver it a la posición inicial, es decir aquí:

Código (cpp) [Seleccionar]
if (itb == B.end())
{
   A.erase(it->first);
   map<int, bool>::iterator it = A.begin();
}


Si no me equivoco debería ser:
Código (cpp) [Seleccionar]
if (itb == B.end())
{
   A.erase(it->first);
   it = A.begin();
}


Ya que ese iterador solo está definido en ese ámbito, y elimina la visibilidad del iterador it que declaraste antes y evidentemente no modificas el valor del que quieres modificar. Por tanto el iterador it original no vuelve a la posición inicial nunca.

Hay otro problema y es que cuando modificas eso(si no lo modificas con la misma entrada te da un error de violación de acceso a la memoria) y pulsas intro se crea un bucle infinito (no sé donde está el fallo). Para comprobarlo puedes usar la siguiente entrada:
1
Salida de la funcion muestra: 1
2
Bucle infinito


Saludos.
Regístrate en

Orubatosu

Vale... el problema era tan "simple" como eso, el iterador ya estaba definido, y al redifinirlo la lio.

Hare un par de experimentos a ver, aunque el programa en realidad funciona sin borrar nada, pero quiero tener claro que hacer en caso de que SI quiera borrar, o no liarla con los iteradores.

Lo cómico es que al borrar el elemento que apunta al iterador, este se quede "en el aire", debería (pienso yo) o desaparecer o reubicarse en otra posición, pero no quedarse "ahi colgado"
"When People called me freak, i close my eyes and laughed, because they are blinded to happiness"
Hideto Matsumoto 1964-1998

avesudra

Cita de: Orubatosu en 19 Diciembre 2014, 18:02 PM
Vale... el problema era tan "simple" como eso, el iterador ya estaba definido, y al redifinirlo la lio.

Hare un par de experimentos a ver, aunque el programa en realidad funciona sin borrar nada, pero quiero tener claro que hacer en caso de que SI quiera borrar, o no liarla con los iteradores.

Lo cómico es que al borrar el elemento que apunta al iterador, este se quede "en el aire", debería (pienso yo) o desaparecer o reubicarse en otra posición, pero no quedarse "ahi colgado"

Pero ahora da un error mas raro todavía, hace un bucle infinito muy muy raro, no sé que puede estar pasando.

Saludos.
Regístrate en

Orubatosu

Pues no lo se... acabo de intentar la modificación que propones, y ahora funciona correctamente, borrando y sin "volar" el programa  :huh:

Ten en cuenta que la función "mostrar" no es igual en ambas versiones, inicialmente solo saco los valores de las claves (ignorando los valores asociados), mientras que en la segunda he modificado esa función (y no te lo he comentado  :-X)

Yo así veo que funciona


#include <iostream>
#include <sstream>
#include <map>
using namespace std;

map <int, bool> separa (string& s){
    istringstream S (s);
    map<int, bool> ret;
    int n;
    while (S >> n){
        ret[n] = false;
    }
    return ret;
}

void muestra (const map<int, bool>& m){
    map<int, bool>::const_iterator itm = m.begin();
    for (; itm != m.end(); itm++){
        cout << itm->first << ' ';
    }
    cout << endl;
}

int main(){
    string entrada;
    map <int, bool> A;
    map <int, bool> B;
    getline (cin, entrada);
    cout << entrada << endl;
    A = separa (entrada);
    while (getline (cin, entrada)){
        B = separa (entrada);
        map<int, bool>::iterator it = A.begin();
        for (; it != A.end(); it++){
            map<int, bool>::iterator itb = B.find(it->first);
            if (itb == B.end()){
                A.erase(it->first);
                it = A.begin();
            }
        }
        muestra (A);
    }
}


"When People called me freak, i close my eyes and laughed, because they are blinded to happiness"
Hideto Matsumoto 1964-1998

avesudra

Cita de: Orubatosu en 19 Diciembre 2014, 18:34 PM
Pues no lo se... acabo de intentar la modificación que propones, y ahora funciona correctamente, borrando y sin "volar" el programa  :huh:

Ten en cuenta que la función "mostrar" no es igual en ambas versiones, inicialmente solo saco los valores de las claves (ignorando los valores asociados), mientras que en la segunda he modificado esa función (y no te lo he comentado  :-X)

Yo así veo que funciona

Que va a mi no me va, mete primero un 1 y luego un 2, verás como al intentar meter otro valor no te deja :S

Un saludo.
Regístrate en

Orubatosu

Errr... a ver, es que esa no es la idea del programa

La idea del programa es que pongas una secuencia de numeros, tal que así

1 2 3 5 8 9 7 5 8 21 55 33 22 7 -10 25 (intro)
5 7 25 13 8 22 (intro)
1 2 5 9 78 22 (intro)

Y va diciéndote los números que están en todas las líneas

Si metes solo un numero, y luego otro, obviamente ya no importa lo que pongas, todo lo que introduzcas a partir de ahí no aparece en todas las líneas.

Claro, no he puesto medidas para evitar un uso "diferente" porque solo estoy haciendo problemas sin mirar de evitar este tipo de cosas

La "idea" es un programa que filtre secuencias diferentes y mantenga solo los números que aparecen en todas las entradas
"When People called me freak, i close my eyes and laughed, because they are blinded to happiness"
Hideto Matsumoto 1964-1998

avesudra

Ahhh entonces solucionado.

Un saludo  ;D
Regístrate en