2010-10-08 8 views
1

j'ai écrit cette méthode pour trouver le mineur d'une matrice creuse:Effacement d'un élément du vecteur lors de l'itération C++

SpMatrixVec SparseMatrix::minor(SpMatrixVec matrix, int col) const{ 

    SpMatrixVec::iterator it = matrix.begin(); 

    int currRow = it->getRow(); 

    int currCol = col; 

    while(it != matrix.end()) { 

     if(it->getRow() == currRow || it->getCol() == currCol){ 
      matrix.erase(it); 
     } 
     // if we have deleted an element in the array, it doesn't advance the 
     // iterator and size() will be decreased by one. 
     else{ 
      it++; 
     } 

    } 

    // now, we alter the cells of the minor matrix to be of proper coordinates. 
    // this is necessary for sign computation (+/-) in the determinant recursive 
    // formula of detHelper(), since the minor matrix non-zero elements are now 
    // in different coordinates. The row is always decreased by one, since we 
    // work witht he first line, and the col is decreased by one if the element 
    // was located after 'col' (which this function receives as a parameter). 

    //change the cells of the minor to their proper coordinates. 
    for(it = matrix.begin(); it != matrix.end(); it++){ 

     it->setRow(it->getRow()-1); 

     int newY; 
     newY = (it->getCol() > col) ? it->getCol() + 1 : it->getCol(); 

     it->setCol(newY); 
    } 
    return matrix; 

} 

Maintenant, je suis sans doute faire quelque chose de mal, car en arrivant à la deuxième interation du while boucle, le programme se bloque. L'idée de base était de passer en revue le vecteur, et voir si c'est la coordonnée pertinente, et si oui, de le supprimer. Je n'incrémente l'itérateur que s'il n'y a pas eu de suppression (et dans ce cas, le vecteur devrait mettre à jour l'itérateur pour pointer l'élément suivant ... à moins que je me trompe).

Où est le problème?

Merci beaucoup.

+0

Comment sont définis SpMatrixVec et Matrice Creuse? – luke

+0

it ++ :(++ it :) bien sûr ce n'est pas le problème, mais le problème a déjà été correctement traité –

+0

Si ceci est un vecteur, vous ferez mieux d'utiliser http://en.wikipedia.org/ wiki/Erase-remove_idiom car cela ne ferait que copier les choses une seule fois, alors que chaque effacement individuel dans votre code devrait copier tous les éléments suivants. – UncleBens

Répondre

-2

Vous ne pouvez pas modifier une collection pendant que vous itérez entre ses éléments. Utilisez une autre collection temporaire pour stocker les résultats partiels.

edit: Encore mieux, utilisez un foncteur pour supprimer des éléments: remove_if Vous écrivez la condition.

+0

C'est tout simplement faux. Vous pouvez le modifier en itérant, il vous suffit de vous assurer que les itérateurs ne sont pas invalidés pendant que vous le faites. – ereOn

+0

Non, il est possible de le faire. Il suffit de stocker la valeur de retour de 'erase' pour obtenir un nouvel itérateur valide. – Benoit

5

erase invalide votre itérateur. Ne it = matrix.erase(it) à la place.

9

erase() invalide votre itérateur.

Vous devez mettre à jour it en utilisant la valeur de retour de erase() pour que la boucle travail:

while(it != matrix.end()) { 

    if(it->getRow() == currRow || it->getCol() == currCol){ 
     //matrix.erase(it); 
     it = matrix.erase(it); // Here is the change 
    } 
    // if we have deleted an element in the array, it doesn't advance the 
    // iterator and size() will be decreased by one. 
    else{ 
     //it++; 
     ++it; // ++i is usually faster than i++. It's a good habit to use it. 
    } 

} 
+0

+1 mais '++ it' est mieux –

+0

@Steve Townsend: Absolument, je ne vérifiais pas d'autres" erreurs "dans le code, mais vous avez en effet absolument raison. Fixé. Merci. – ereOn

+0

Ce code est un peu dangereux, vous devez détecter si l'itérateur pointe vers le dernier élément du vecteur et le gérer spécifiquement. J'ai appris cela à la dure en utilisant cet exemple ;-) – Benj