Rechercher : dans
Par :

[Algo C++] Anagrammes

Dernière réponse le 20 aoû 2009 à 15:23:40 KX, le 19 aoû 2009 à 20:04:58 
 Signaler ce message aux modérateurs

Bonjour,

Je suis en train de faire un programme qui recherche des anagrammes (j'entends par anagramme un mot qui peut s'écrire avec les lettres d'un autre). Après de nombreux essais je pensais avoir définitivement trouvé comment écrire ma fonction principale isAnagram, mais je viens de terminer le reste du code et je m'aperçois qu'en fait elle me donne des faux positifs (et peut-être des faux négatifs mais c'est moins évident à déterminer)

Si quelqu'un pouvait regarder mon code et me dire comment le corriger... Merci !

// stringD.h

class stringD
{
private:
    s1,s2:std::string;

// s1 et s2 ne contiennent que des lettres majuscules entre 'A' et 'Z'
// s2 contient les mêmes lettres que s1 mais triées dans l'ordre alphabétique

public:
    size_t size(void);
    bool isAnagram(stringD s);
};

// stringD.cpp

bool stringD::isAnagram(stringD s) // this* est-il écrit avec les lettres de s ?
{
    if (size()>s.size()) return false;

    for (unsigned i=0,j=0; j<s.size(); i++, j++)
    {
        while (s.s2[j]<s2[i])
            j++;

        if (s2[i]!=s.s2[j])
            return false;
    }
    return true;
}
Un exemple de faux positif :
x.s1="LETTRES", x.s2="EELRSTT"
y.s1="LUTTEUR", y.s2="ELRTTUU"

bool b=x.isAnagram(y); // b==true !?
La confiance n'exclut pas le contrôle 
Configuration: Windows Vista SP2 / Qt 4.5.2

Meilleures réponses pour « [Algo C++] Anagrammes » dans :
La compilation et les modules en C et en C++ VoirCet article a pour vocation d'introduire les notions de bases de la compilation en C et en C++ et de la programmation modulaire. Il permet de mieux comprendre les messages d'erreur du compilateur. Les notions abordées ici sont indépendantes du...
Vérifier si un nombre entier est un nombre premier en C VoirDéfinition nombre premier Algorithme 1 : les diviseurs compris entre 2 et N-1 seront testés Algorithme 2 : les diviseurs pairs ne seront pas testés, la recherche se limitant aux diviseurs impairs Algorithme 3 : les diviseurs impairs jusqu'à la...
[Langage C] C/C++ Erreur de segmentation VoirQu'est ce qu'une erreur de segmentation Vous êtes en train de développer une application sous Linux en C/C++. Tout va bien, ça compile, les oiseaux chantent. Donc vous lancez votre application pour la tester. Et vous obtenez l'un de ces deux...
Télécharger Visual C++ Express VoirVisual C++ Express est une version "gratuite" et allégée de Visual Studio ; l'utilisation requiert l'inscription sur le site de Microsoft. Cet environnement de développement permet de créer des application Win32 ou du .NET C.
Langage C++ - Les types de données VoirLes types de données Les données manipulées en langage C++, comme en langage C, sont typées, c'est-à-dire que pour chaque donnée que l'on utilise (dans les variables par exemple) il faut préciser le type de donnée, ce qui permet de connaître...
Les chaînes de caractères en C++ VoirQu'est-ce qu'une chaîne de caractères ? Une chaîne de caractères (appelée string en anglais) est une suite de caractères, c'est-à-dire un ensemble de symboles faisant partie du jeu de caractères, défini par le code ASCII. En langage C++, une...
Les structures en langage C VoirDifférence entre une structure et un tableau Un tableau permet de regrouper des éléments de même type, c'est-à-dire codés sur le même nombre de bits et de la même façon. Toutefois, il est généralement utile de pouvoir rassembler des éléments de...

1

Char Snipeur, le 20 aoû 2009 à 08:23:56

Je ne comprend pas ton algorithme.
Pourtant, si tu as les lettres du mot trié alphabétiquement, il suffit de voir si les chaine s2 sont identiques.
Deux mots sont anagramme lorsqu'ils contiennent les même lettres. Et si ils contients les même lettres, leur trie alphabétique est le même.
ta fonction devrais être juste :
return s2==s.s2; Salutation ! (il faut bien que vous compreniez que j'ai TOUJ­OURS raison)
Char Snipeur

Répondre à Char Snipeur

2

KX, le 20 aoû 2009 à 13:49:22

Je suis d'accord sur la vraie définition d'un anagramme.
Cependant comme je l'ai dit j'entends par anagramme un mot qui peut s'écrire avec les lettres d'un autre, par exemple si je joue au Scrabble, j'ai 7 lettres et je cherche tous les mots que je puisse avoir avec ces 7 lettres.
Il y aura donc dans mes résultats d'une part des anagrammes mais aussi des mots plus courts...

Le problème c'est que mon algorithme renvoie true à des mots this* qui ne contiennent pas les lettres des s.
Ce qui me laisse encore plus perplexe, c'est que avec le même mot, si je lance plusieurs fois de suite la recherche sur le dictionnaire entier, il ne me trouve pas toujours les même faux positifs. C'est à dire qu'avec le mot "LETTRES" j'ai parfois 46 résultats positifs dans le dictionnaire, parfois 64, parfois entre les deux... Donc bien sûr les vrais "anagrammes" apparaissent toujours mais les faux positifs semblent aller et venir de façon aléatoire !

Sur l'idée mon algorithme compare des mots qui peuvent donc être de taille différente this* de taille <= à s d'où ma première ligne. Par exemple, "BON" est - selon ma définition - anagramme de "BONJOUR".
La recherche compare donc this->s2="BNO" et s.s2="BJNOORU.
Je parcours donc les deux mots en comparant les deux première lettres, ici égales -> je compare les deux deuxièmes, différentes -> j'incrémente mon "curseur" sur s.s2; pour comparer O et O, en excluant donc la lettre J.
Et je continue jusqu'à la fin, sauf si je trouve par exemple à la place du J un P, ce qui signifierait qu'il n'y ait pas de O dans s, et que this ne peut donc pas être "anagramme" de s.

Il semble que le problème vient de mon return true; final, puisque apparemment mes faux positifs sont composés de lettres de s, et uniquement de lettres supérieurs à la plus grande lettre de s !
Par exemple "LUTTEUR-ELRTTUU" est un faux positif de "LETTRES-EELRSTT" composé avec deux U supérieurs au T qui était la dernière lettre de EELRSTT...

J'arrive bien à analyser l'erreur, mais je ne vois pas comment corriger mon problème, ni même comment le traiter autrement... La confiance n'exclut pas le contrôle 

Répondre à KX

3

KX, le 20 aoû 2009 à 14:20:26
  • +1

Mon problème ne vient pas de là mais si ça peut aider, voici mon constructeur stringD :

#include <string>
#include <algorithm>

stringD::stringD(const std::string s):s1(s),s2(s) // s doit être un mot en majuscule
{
    std::sort(s2.begin(),s2.end());
}
La confiance n'exclut pas le contrôle 

Répondre à KX

4

Char Snipeur, le 20 aoû 2009 à 14:32:38

OK, je comprends mieux. Je n'avais pas compris ta première explication.
Comme tes lettres son ordonnées, c'est déjà plus facile.
pour que ça soit plus clair, mieux vaut découper ta boucle.

bool stringD::isAnagram(stringD s) // this* est-il écrit avec les lettres de s ?
{
    if (size()>s.size()) return false;
    int j=0;
    for (unsigned i=0; i<size(); i++)
    {
        while (s.s2[j]<s2[i])
            j++;

        if (s2[i]!=s.s2[j])
            return false;
       else j++;
    }
    return true;
}

Mais tu peux faire ça aussi en pile. (écriture en algorithme, je ne suis pas certain des fonctions utilisées)
bool stringD::isAnagram(stringD s) // this* est-il écrit avec les lettres de s ?
{
    if (size()>s.size()) return false;
    for(int i=0;i<s.size();++i)
    {
          int pos=s.s2.find(s[i]);
          if(pos==std::string::npos) return false;
          else s2.remove(pos);
    }
    return true;
} 
Salutation ! (il faut bien que vous compreniez que j'ai TOUJOURS raison)
Char Snipeur

Répondre à Char Snipeur

5

 KX, le 20 aoû 2009 à 15:23:40

Merci, ton premier algorithme ne marche pas mieux, mais en partant sur l'idée du deuxième algorithme j'ai réussi à modifier et à obtenir les bons résultats, et de plus avec cette méthode j'ai l'impression que je peux m'abstenir du tri préalable des lettres, ce qui me ferai gagner temps/mémoire lors du chargement du dictionnaire

bool stringD::isAnagram(stringD s)
{
    if (size()>s.size()) return false;    
    for(unsigned i=0;i<size();++i)
    {
        unsigned pos=s.s2.find(s2[i]);
        if(pos==std::string::npos) return false;
          else s.s2.erase(pos,1);
    }
    return true;
}
Merci encore ! La confiance n'exclut pas le contrôle 

Répondre à KX