elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Usando Git para manipular el directorio de trabajo, el índice y commits (segunda parte)


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  Como intercambiar valores de un iterator en C++
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] 2 Ir Abajo Respuesta Imprimir
Autor Tema: Como intercambiar valores de un iterator en C++  (Leído 4,332 veces)
alpachino98

Desconectado Desconectado

Mensajes: 37


Valar Morghulis


Ver Perfil
Como intercambiar valores de un iterator en C++
« en: 20 Enero 2019, 01:28 am »

Hola,
Si alguien puede ayudarme en como intercambiar dos valores de una lista (debe estar ordenada alfabéticamente). Esta lista contiene objetos de una clase contacto.
Les dejo por aquí los atributos de la clase contactos.
Código:
private:
  string nombre;// Cadena con el contenido de la palabra
  int nTlf;

Atributos de la clase Agenda ( es la que contiene la lista).
Código:
private:
  list<Contacto> listapal;// La lista STL con los contactos de la agenda.
  bool encuentraContacto(const string &, list<Contacto>::iterator &);
 
Este es el método que debe ordenar la lista <listapal>.
Código:
void/*list<Contacto>*/ Agenda:: ordenaListas()
{
list<Contacto> :: iterator aux;
Contacto contI;
Contacto contJ;

for (list<Contacto>::iterator it=listapal.begin();it != listapal.end(); it++)
{
for (list<Contacto>::iterator jt=it;jt!=listapal.end(); jt++)
{
jt++;
contI=*it;
contJ=*jt;

if(!(contI.getNombre()<=contJ.getNombre()))
{
//Primer intento
/* *aux=*it;
*it=*jt;
*jt=*aux;*/

                                //Segundo intento
pos->setNombre(it->getNombre());
pos->setNumeroTelefono(it->getNumeroTelefono());

it->setNombre(jt->getNombre());
it->setNumeroTelefono(jt->getNumeroTelefono());

jt->setNombre(pos->getNombre());
jt->setNumeroTelefono(pos->getNumeroTelefono());

}
}}

Les he puesto las dos cosas que creo que más sentido tendrían. El problema es que al compilar y ejecutarlo se queda congelado cuando intenta ordenar la lista.

Lo que pretendo hacer es usar el método de la burbuja. Les dejo una idea de lo que quisiera hacer pero con iteradores.
Código:
for (i=0; i<n-1; i++)
{
   for (j=i+1; j<n; j++)
  {
    if(V[i]>V[j])
    {
     aux = V[i];
     V[i] = V[j];
     V[j] = aux;
    }
  }
}




En línea

Loretz

Desconectado Desconectado

Mensajes: 117


Ver Perfil
Re: Como intercambiar valores de un iterator en C++
« Respuesta #1 en: 20 Enero 2019, 01:54 am »

Mira, yo creo que en tu segundo for...
cuando haces:
Código:
jt=it;
estás asignando it a jt, y entonces, con
Código:
jt++;
lo que haces es incrementar los dos, jt apuntará al siguiente elemento en la lista, igual que it.

Luego...
Código:
if(!(contI.getNombre()<=contJ.getNombre()))
jamás se cumplirá porque contI y contJ son iguales (mismo nombre, mismo nTlf).

Y como esa condición jamás se cumple, el ciclo for interno va incrementando a jt (y también a it, que es el mismo iterador) hasta hacerlos igual a listapal.end().

Y ahora que it es == a listapal.end(), cuando vuelve a ejecutarse el incremento del ciclo for externo, it va a ser el siguiente de listapal.end() (undefined behavior), que va a cumplir con la condición
Código:
it != listapal.end();
porque efectivamente es distinto, es uno más allá que más allá del último.

¿Y entonces? El ciclo for más externo jamás se detendrá... (bueno, sí se detendrá, más temprano que tarde el sistema operativo se encargará de humillarte convenientemente).

Pregunta. La std::list ya tiene su método sort(), ¿por qué no lo usas?



En línea

alpachino98

Desconectado Desconectado

Mensajes: 37


Valar Morghulis


Ver Perfil
Re: Como intercambiar valores de un iterator en C++
« Respuesta #2 en: 20 Enero 2019, 02:02 am »

Vale ahora miraré como puedo solucionar todo eso que me has dicho, no había caído en todo eso que has dicho y creo que tienes toda la razón.
Uso este método y no el de sort porque sort no puede ordenar objetos de la clase contacto, no he encontrado ninguna manera de decirle que quiero que lo ordene segun el atributo nombre. Si sabes algún modo de hacerlo, en plan operador ternario al que se le pasa la condición o algo asi.

Muchas gracias.
En línea

Loretz

Desconectado Desconectado

Mensajes: 117


Ver Perfil
Re: Como intercambiar valores de un iterator en C++
« Respuesta #3 en: 20 Enero 2019, 03:48 am »

Un ejemplo con el estándar C++17

Código:
#include <iostream>
#include <string>
#include <list>

struct Contacto {
    std::string nombre;
    int nTlf;
};

void mostrar(const std::list<Contacto>& Agenda)
{
    for (const auto& [n, t] : Agenda) {
        std::cout << n << " -> " << t << '\n';
    }
    std::cout << '\n';
}

int main()
{
    std::list<Contacto> Agenda{ {"Juan", 14}, {"Ana", 23}, {"Susana", 19}, {"Abel", 22} };
    std::cout << "desordenada:\n";
    mostrar(Agenda);

    // ordenada por nombre:
    Agenda.sort([](const auto& c1, const auto& c2) { return c1.nombre < c2.nombre; });
    std::cout << "ordenada:\n";
    mostrar(Agenda);
}
En línea

alpachino98

Desconectado Desconectado

Mensajes: 37


Valar Morghulis


Ver Perfil
Re: Como intercambiar valores de un iterator en C++
« Respuesta #4 en: 20 Enero 2019, 12:30 pm »

No se si es que no lo he entedido mucho pero si hago :
Código:
listapal.sort([](const Contacto& c1, const Contacto& c2) { return c1.nombre <c2.nombre; });

Me da error:
Código:
[Error] no matching function for call to 'std::list<Contacto>::sort(Agenda::imprimeAgenda()::<lambda(const Contacto&, const Contacto&)>)'

Y si lo hago tal cual lo tienes tu:
Código:
listapal.sort([](const auto& c1, const auto& c2) { return c1.nombre <c2.nombre; });

Me da estos errores:
Código:
[Error] request for member 'nombre' in 'c1', which is of non-class type 'const int'

Código:
Error] request for member 'nombre' in 'c2', which is of non- type 'const int'

Código:
[Error] no matching function for call to 'std::list<Contacto>::sort(Agenda::imprimeAgenda()::<lambda(const int&, const int&)>)'

Y eso que he cambiado el atributo nombre a publico(ya se que no debería pero es que con el getNombre() me dice que no existe getNombre()).
Pero es que tu código tampoco me funciona, no entiendo nada. No debe ser tan complicado :-\
« Última modificación: 20 Enero 2019, 12:45 pm por alpachino98 » En línea

Loretz

Desconectado Desconectado

Mensajes: 117


Ver Perfil
Re: Como intercambiar valores de un iterator en C++
« Respuesta #5 en: 20 Enero 2019, 13:43 pm »


Código:
listapal.sort([](const Contacto& c1, const Contacto& c2) { return c1.nombre <c2.nombre; });
Generic lambda está a partir del estándar C++14:
https://isocpp.org/wiki/faq/cpp14-language#generic-lambdas

En línea

alpachino98

Desconectado Desconectado

Mensajes: 37


Valar Morghulis


Ver Perfil
Re: Como intercambiar valores de un iterator en C++
« Respuesta #6 en: 20 Enero 2019, 14:04 pm »

En visual studio si me funciona pero prefiero hacerlo sin la lambda, en java hemos visto lambdas pero el estandar que usamos es c++ 11. He cambiado eso de adelantar el iterador jt y he cambiado la condicion del if. Sigue sin funcionar pero ya no se que hacer, supongo que lo dejare sin ordenar o lo pondré todo en una misma clase ( aunque prefería hacerlo en dos).

Código:
for (list<Contacto>::iterator it=listapal.begin();it != listapal.end(); it++)
{
for (list<Contacto>::iterator jt=it;jt!=listapal.end()--; jt++)
{
//jt++;
contI=*it;
contJ=*jt;

if(contI.getNombre().compare(contJ.getNombre())>0)
{

/* *pos=*it;
*it=*jt;
*jt=*pos;*/

pos->setNombre(it->getNombre());
pos->setNumeroTelefono(it->getNumeroTelefono());

it->setNombre(jt->getNombre());
it->setNumeroTelefono(jt->getNumeroTelefono());

jt->setNombre(pos->getNombre());
jt->setNumeroTelefono(pos->getNumeroTelefono());


}
« Última modificación: 20 Enero 2019, 14:08 pm por alpachino98 » En línea

K-YreX
Moderador
***
Desconectado Desconectado

Mensajes: 1.008



Ver Perfil
Re: Como intercambiar valores de un iterator en C++
« Respuesta #7 en: 20 Enero 2019, 16:15 pm »

La buena noticia es que es posible hacer lo que quieres hacer, el único problema es que estabas teniendo un problema con el uso de los iteradores. Si asignas un iterador a otro e incrementas uno de ellos, no se incrementa el otro (solo lo aclaro)

Código
  1. void Agenda::ordenar(){
  2.    Contacto auxiliar;
  3.    for(list<Contacto>::iterator it1 = listapal.begin(); it1 != --listapal.end(); it1++)
  4.        for(list<Contacto>::iterator it2 = ++it1--; it2 != listapal.end(); it2++)
  5.            if(it1->getNombre() > it2->getNombre()){
  6.                auxiliar = *it1;
  7.                *it1 = *it2;
  8.                *it2 = auxiliar;
  9.            }
  10. }

Ya sé que puede parecer muy raro eso de ++it1-- pero es la forma más rápido de hacerlo. Te lo explico por si lo quieres hacer de otra forma:
Lo normal es que si el bucle externo se controla con <i>, el bucle interno empieza siempre en <i+1>. Al ser iteradores de una lista no se puede hacer <it2 = it1+1>... Entonces cómo lo arreglamos? Con el uso de los incrementos en prefijo y sufijo:
  • En prefijo primero se incrementa/decrementa y luego se asigna.
  • En sufijo primero se asigna y luego se incrementa/decrementa.
Entonces así conseguimos incrementar <it1> en 1, después se asigna a <it2> y después se decrementa <it1> para dejarlo igual. Suerte :-X
En línea

Código
  1. cout << "Todos tenemos un defecto, un error en nuestro código" << endl;
alpachino98

Desconectado Desconectado

Mensajes: 37


Valar Morghulis


Ver Perfil
Re: Como intercambiar valores de un iterator en C++
« Respuesta #8 en: 20 Enero 2019, 17:57 pm »

Vale muchas gracias, es verdad, me he mareado un poco ahí con los iteradores. He probado tu código y sigo con el mismo problema, el resto del programa funciona correctamente pero ya no se si puede que se quede pillado por otra cosa o que...el caso es que cada vez que intenta ordenar se queda congelado hasta que el sistema operativo decide mandarlo a la *****.  >:D
En línea

K-YreX
Moderador
***
Desconectado Desconectado

Mensajes: 1.008



Ver Perfil
Re: Como intercambiar valores de un iterator en C++
« Respuesta #9 en: 20 Enero 2019, 17:59 pm »

Yo he creado un programa similar al que mostrabas pero más sencillo para probar el ordenamiento y me ha funcionado sin problemas. Deja tu código a ver cómo te ha quedado por si el fallo está en otra cosa. :-X
En línea

Código
  1. cout << "Todos tenemos un defecto, un error en nuestro código" << endl;
Páginas: [1] 2 Ir Arriba Respuesta Imprimir 

Ir a:  

WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines