Как к ускорению простой метод (предпочтительно, не изменяя интерфейсы или структуры данных)?

У меня есть некоторые структуры данных:

  • all_unordered_m большой вектор, содержащий все строки, в которых я нуждаюсь (все отличающиеся)
  • ordered_m маленький вектор, содержащий индексы подмножества строк (все отличающиеся) в бывшем векторе
  • position_m отображает индексы объектов от первого вектора до их положения во втором.

string_after(index, reverse) метод возвращает строку, на которую ссылается ordered_m после all_unordered_m[index].

ordered_m считается круговым, и исследуется в естественном или обратном порядке в зависимости от второго параметра.

Код - что-то как следующее:

struct ordered_subset {
    // [...]

    std::vector<std::string>& all_unordered_m; // size = n >> 1
    std::vector<size_t> ordered_m;             // size << n
    std::tr1::unordered_map<size_t, size_t> position_m;  

    const std::string&
    string_after(size_t index, bool reverse) const
    {
        size_t pos = position_m.find(index)->second;
        if(reverse)
            pos = (pos == 0 ? orderd_m.size() - 1 : pos - 1);
        else
            pos = (pos == ordered.size() - 1 ? 0 : pos + 1);
        return all_unordered_m[ordered_m[pos]];
    }
};

Учитывая, что:

  • Мне действительно нужны все структуры данных для других целей;
  • Я не могу изменить их, потому что я должен получить доступ к строкам:
    • их идентификатором в all_unordered_m;
    • их индексом в различном ordered_m;
  • Я должен знать положение строки (определенный, он - положение в первом векторе), внутри ordered_m вектор;
  • Я не могу изменить интерфейс string_after, не изменяя большую часть программы.

Как я могу убыстриться string_after метод, который называют миллиардами времен и съедает выше на приблизительно 10% времени выполнения?

Править: Я попытался делать position_m a vector вместо a unordered_map и использование следующего метода для предотвращения переходов:

string_after(size_t index, int direction) const
{
  return all_unordered_m[ordered_m[
      (ordered_m.size()+position_m[index]+direction)%ordered_m.size()]];
}

Изменение в position_m, кажется, является самым эффективным (я не уверен, что устранение ответвлений имело любое значение, я испытываю желание сказать, что код более компактен, но одинаково эффективен с тем отношением).

8
задан baol 15 May 2015 в 20:18
поделиться

2 ответа

поиск вектора быстро выполняется. Вызовы size () и простая арифметика стремительно развиваются. Для сравнения, поиск по карте медленный, как мертвая черепаха с бетонным блоком на спине. Я часто видел, как они становятся узким местом в таком простом коде, как этот.

Вместо этого вы можете попробовать unordered_map из TR1 или C ++ 0x (заменяющая хеш-таблица map ) и посмотреть, имеет ли это значение.

3
ответ дан 5 December 2019 в 22:17
поделиться

Что ж, в таких случаях (небольшая функция, которая часто вызывается) каждая ветвь может быть очень дорогой. На ум приходят две вещи.

  1. Не могли бы вы опустить параметр reverse и сделать его двумя отдельными методами? Это имеет смысл только в том случае, если это не просто подталкивает выражение if к вызывающему коду.
  2. Попробуйте следующее для вычисления pos : pos = (pos + 1)% orders_m.size () (это для прямого случая). Это работает, только если вы уверены, что pos никогда не переполняется при его увеличении.

В общем, в таких случаях старайтесь заменять ветвления арифметическими операциями, это может значительно ускорить процесс.

3
ответ дан 5 December 2019 в 22:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: