Скажите `string :: operator ==`, чтобы начать сравнение в конце строки - PullRequest
7 голосов
/ 30 ноября 2010

Возможно ли / (относительно) легко / std ™ начать сравнение в конце строки, или я должен написать свою собственную функцию для этого? Конечно, это было бы относительно просто, но, тем не менее, я доверял бы стандартной реализации библиотеки в любое время.

Конец строки почти уникален, а фронт довольно распространен, и это единственная причина, по которой мне нужна эта «оптимизация».

Спасибо!

Ответы [ 6 ]

18 голосов
/ 30 ноября 2010

Лучшее, что я могу себе представить, это str1.size() == str2.size() && std::equal(str1.rbegin(), str1.rend(), str2.rbegin())

3 голосов
/ 30 ноября 2010

В зависимости от длины строк (и вашего компилятора), вам лучше придерживаться operator==. В Visual C ++ v10 это сводится к вызову memcmp через char_traits::compare, который (при оптимизации) будет сравнивать целевые диапазоны байтов в блоках, вероятно, столько же байтов за раз, сколько поместится в регистр 8 для 32/64-бит).

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));
    }

Между тем, std::equal (самая хорошая альтернатива) выполняет побайтовое сравнение. Кто-нибудь знает, будет ли он оптимизирован таким же образом, поскольку они являются обратными итераторами? В лучшем случае обработка выравнивания является более сложной, поскольку начало диапазона не гарантируется выровненным.

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);
    }

См. Ответ @ greyfade здесь , чтобы узнать о некотором цвете в GCC.

3 голосов
/ 30 ноября 2010

Вы можете использовать std :: equal в сочетании с std :: basic_string :: reverse_iterator (rbegin, rend).

Однако это уместно только в том случае, если строки имеют одинаковую длину (поэтому вам необходимо сначала проверить размеры) и только для равенства строк (поскольку наиболее значимое различие будет последним, сравниваемым во время итерации).

Пример:

bool isEqual = s1.size() == s2.size() && std::equal( s1.rbegin(), s1.rend(), s2.rbegin());
2 голосов
/ 30 ноября 2010

Если вы хотите сначала перевернуть его, я бы предложил сначала перевернуть строку с помощью reverse (), а затем начать сравнение с помощью string.compare () или использовать собственный алгоритм.Однако reverse () занимает некоторое время и требует много ресурсов процессора, поэтому я предлагаю свою функцию для ее обработки.Начните цикл с i, равным string.length (), а затем выполните обратный отсчет, используя --i, и сравните.

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 голосов
/ 30 ноября 2010

вижу два варианта:

  1. Напишите свою собственную функцию сравнения и вызовите ее.

  2. Написать класс обертки вокруг std :: string и реализуйте operator== для этого класса, чтобы иметь желаемое поведение.

Второй, вероятно, излишний.

0 голосов
/ 30 ноября 2010

Вы должны написать свою собственную функцию для этого. Вы можете повернуть вспять, как говорит Lost, но это не будет оптимизацией, если вы не будете хранить эту перевернутую строку и сравнивать ее несколько раз. Даже в этом случае это не будет улучшением по сравнению с написанием собственного, которое просто перебирает строки в обратном порядке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...