C++ получить индекс элемента массива по значению
до сих пор я хранил массив в векторе, а затем перебирал вектор, чтобы найти соответствующий элемент, а затем возвращал индекс.
есть ли более быстрый способ сделать это на C++? Структура STL, которую я использую для хранения массива, на самом деле не имеет для меня значения (это не должен быть вектор). Мой массив также уникален (без повторяющихся элементов) и упорядочен (например, список дат, идущих вперед во времени).
2 ответов
поскольку элементы отсортированы, вы можете использовать двоичный поиск, чтобы найти соответствующий элемент. Стандартная библиотека C++ имеет std::lower_bound
алгоритм, который может быть использован для этой цели. Я бы рекомендовал обернуть его в свой собственный алгоритм бинарного поиска, для ясности и простоты:
/// Performs a binary search for an element
///
/// The range `[first, last)` must be ordered via `comparer`. If `value` is
/// found in the range, an iterator to the first element comparing equal to
/// `value` will be returned; if `value` is not found in the range, `last` is
/// returned.
template <typename RandomAccessIterator, typename Value, typename Comparer>
auto binary_search(RandomAccessIterator const first,
RandomAccessIterator const last,
Value const& value,
Comparer comparer) -> RandomAccessIterator
{
RandomAccessIterator it(std::lower_bound(first, last, value, comparer));
if (it == last || comparer(*it, value) || comparer(value, *it))
return last;
return it;
}
(стандартная библиотека C++ имеет std::binary_search
, но он возвращает bool
: true
если диапазон содержит элемент false
иначе. Это не полезно, если вы хотите, чтобы итератор элемент.)
как только у вас есть итератор для элемента, вы можете использовать std::distance
алгоритм вычисления индекса элемента в диапазоне.
оба этих алгоритма одинаково хорошо работают с любой последовательностью случайного доступа, включая оба std::vector
и обычные массивы.
если вы хотите связать значение с индексом и быстро найти индекс, вы можете использовать std::map
или std::unordered_map
. Вы также можете комбинировать их с другими структурами данных (например,std::list
или std::vector
) в зависимости от других операций, которые вы хотите выполнять на данных.
например, при создании вектора мы также создаем таблицу подстановки:
vector<int> test(test_size);
unordered_map<int, size_t> lookup;
int value = 0;
for(size_t index = 0; index < test_size; ++index)
{
test[index] = value;
lookup[value] = index;
value += rand()%100+1;
}
теперь, чтобы посмотреть индекс вы просто:
size_t index = lookup[find_value];
использование структуры данных на основе хэш-таблицы (например, unordered_map) - довольно классический компромисс пространства/времени и может превзойти двоичный поиск для такого рода операции "обратного" поиска, когда вам нужно сделать много поисков. Другим преимуществом является то, что он также работает, когда вектор несортированный.
для удовольствия : -) я сделал быстрый тест в VS2012RC, сравнивая двоичный код поиска Джеймса с линейным поиском и с использованием unordered_map для поиска, все на векторе:
до ~50000 элементов данная значительно (х3-4) outpeforms двоичный поиск, который демонстрирует ожидаемый o(зарегистрируйте N) поведение, несколько неожиданного результата заключается в том, что unordered_map теряет Это O(1) поведение последние 10000 элементов, предположительно из-за хеширования, возможно реализация вопроса.
EDIT: max_load_factor () для неупорядоченной карты равен 1, поэтому столкновений не должно быть. Разница в производительности между двоичным поиском и хэш-таблицей для очень больших векторов, по-видимому, заключается в кэшировании связанный и варьируется в зависимости от шаблона поиска в бенчмарке.
выбор между std:: map и std:: unordered_map говорит о разнице между упорядоченными и неупорядоченными картами.