2010-11-30 47 views
7

Est-il possible/(relativement) facile/std ™ de commencer à comparer à l'arrière d'une chaîne ou devrais-je écrire ma propre fonction pour cela ? Ce serait relativement simple bien sûr, mais je ferais toujours confiance à une implémentation de bibliothèque standard sur la mienne un jour.Dites `string :: operator ==` pour commencer à comparer à l'arrière de la chaîne

La fin de la chaîne est presque unique, et l'avant est assez commun, c'est la seule raison pour laquelle j'ai besoin de cette "optimisation".

Merci!

Répondre

18

mieux que je peux penser à ce jour est str1.size() == str2.size() && std::equal(str1.rbegin(), str1.rend(), str2.rbegin())

+0

peut-être un jeu sur ce serait d'utiliser string :: rfind au lieu d'égal. – frankc

+0

@frankc: Je ne sais pas si 'str1.rfind (str2) == 0' se comparerait avant ou arrière. Si nous vérifions d'abord que les chaînes sont de longueur égale, il n'y a qu'une seule position à vérifier, donc ça vaut le coup d'essayer. En fait, techniquement, je ne sais pas si 'std :: equal' va vers l'avant ou vers l'arrière quand on l'applique à un itérateur à accès aléatoire, mais j'ai une forte suspicion ... –

+0

ce n'est pas la partie itérateur aléatoire, c'est le fait 'rbegin'et' rend' return * reverse * les itérateurs qui confirment votre suspicion! Merci, je vais avoir un moment "Pourquoi n'ai-je pas pensé à cela" ... – rubenvb

2

Si vous voulez inverser d'abord, je suggérerais d'inverser() pour inverser la chaîne d'abord, puis commencer à comparer en utilisant string.compare() ou utiliser votre propre algorithme. Cependant, reverse() prend un certain temps, et est un processeur intensif, donc je suggère votre propre fonction pour gérer celui-ci. Commencez une boucle avec i égale à string.length(), puis comptez en utilisant --i et comparez.

function stringCompFromBack(string str1, string str2) 
{ 
    if (str1.length() != str2.length) 
    {return false;} 

    for(int i = str1.length() ; i > 0; --i) 
    { 
     if(str1[i] != str2 [i]) 
     {return false;} 
    } 
    return true; 
} 

string str1 = "James Madison"; 
string str2 = "James Ford"; 
bool same = stringCompFromBack(str1, str2); 
+0

Je pense que vous voulez dire 'i> = 0', et en commençant par' length() - 1'. –

+0

Et je passerais les chaînes comme 'const &'; inutile de les copier. – MSalters

0

Vous devez écrire votre propre fonction pour cela. Vous pouvez inverser comme Lost dit, mais ce ne serait pas une optimisation, sauf si vous avez gardé cette chaîne inversée et où comparer plusieurs fois. Même alors, ce ne serait pas une amélioration par rapport à l'écriture de votre propre qui ne fait que répéter les chaînes à l'envers.

3

Vous pouvez utiliser std :: equal en combinaison avec std :: basic_string :: reverse_iterator (rbegin, rend). Cependant, cela n'est pertinent que si les cordes ont la même longueur (donc vous devez d'abord vérifier les tailles) et seulement pour l'égalité des cordes (puisque la différence la plus significative sera la dernière comparée lors de l'itération).

Exemple:

bool isEqual = s1.size() == s2.size() && std::equal(s1.rbegin(), s1.rend(), s2.rbegin()); 
0

Je vois deux options:

  1. Rédigez votre propre fonction de comparaison et d'appel qui. Std :: string, et implémentez le operator== pour que cette classe ait le comportement que vous voulez.

La seconde est probablement trop lourde.

3

En fonction de la durée des chaînes (et de votre compilateur), il est préférable de ne pas dépasser operator==. Sur Visual C++ v10, cela se réduit à un appel memcmp via char_traits::compare, qui est (lorsqu'il est optimisé) va comparer les gammes d'octets cibles en morceaux, probablement autant d'octets à la fois que le ferait un registre (4/8 pour 32/64 bits).

static int __CLRCALL_OR_CDECL compare(const _Elem *_First1, const _Elem *_First2, 
    size_t _Count) 
    { // compare [_First1, _First1 + _Count) with [_First2, ...) 
    return (_CSTD memcmp(_First1, _First2, _Count)); 
    } 

Pendant ce temps, std::equal (le plus alternatif) ne fait un octet par comparaison d'octets. Est-ce que quelqu'un sait si cela va être optimisé de la même manière, car ce sont des itérateurs inversés? Au mieux, la gestion de l'alignement est plus complexe car le début de la gamme n'est pas garanti bien aligné.

template<class _InIt1, 
    class _InIt2> inline 
    bool _Equal(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2) 
    { // compare [_First1, _Last1) to [First2, ...) 
    for (; _First1 != _Last1; ++_First1, ++_First2) 
     if (!(*_First1 == *_First2)) 
      return (false); 
    return (true); 
    } 

pour une couleur sur GCC Voir la réponse de @ greyfade here.