LINUX.ORG.RU

Итерация по unordered_set быстрее чем по vector?

 ,


0

4

Ковыряю алгоритмы на Leetcode. Преобразую vector в unordered_set для кеширования и поиска элементов, ничего сложного. Далее собственно итератор по vector, и проверка есть ли каждый элемент в unordered_set и далее логика если есть.

Запуск кода вываливается на платформе с ошибкой мол алгоритм отработал слишком медленно.

Барабанная дробь - меняем итерацию по массиву на итерацию по unordered_set - алгоритм укладывается во временные рамки. Что за? Есть разумное объяснение? А то все говорят что итерации по массиву быстрее быть не может за счёт кеширования в CPU и предвыборки элементов массива загодя в кеш. Оказывается может.

int func(vector<int>& nums) {
    unordered_set<int> set;

    for (auto n : nums) {
        set.insert(n);
    }

    // Итерация по nums медленнее чем по 'set' !!!
    for (auto n : nums) {
    ...
Ответ на: комментарий от bugfixer

дык оригинальный тест ваще к задаче с псевдоалгокачки чисто понимание ТС чё

в самой задачке(как оказалось с фигой в кармане) тесты более чтоли равновероятные

qulinxao3 ★☆
()
Ответ на: комментарий от anonymous

И у меня свой интерес и своя практика

Дык, а толку то гонять на входе без дупликатов? Когда вы в миллиарды уходите дырок в вас практически не остаётся. Это очень и очень вырожденный случай. Я даже не до конца понимаю какую практическую пользу из этого извлечь можно.

bugfixer ★★★★★
()
Ответ на: комментарий от bugfixer

Я даже не до конца понимаю какую практическую пользу из этого извлечь можно.

Практическое значение «идеального» хеша. Превращение О(1) в O(logn), там где не ждали.

anonymous
()
12 сентября 2025 г.
Ответ на: комментарий от former_anonymous

как же нет, если в примерах к задаче, указанной ниже имеются дубли, а так же в условиях задачи не указывается, что входной массив уникальных чисел...

safocl ★★
()

вроде бы верно зарефакторил:
https://godbolt.org/z/xEbYK3dvz

#include <vector>
#include <unordered_set>
#include <algorithm>
#include <ranges>
#include <functional>
#include <string>

int longestConsecutive(const std::vector<int>& nums) {
    std::unordered_set<int> set(std::from_range_t(), nums);
    
    auto comparatorFn = [&]( auto v  ){ return set.contains( v - 1 ); };
    auto transformToCountFn  = [&]( auto el ){
                            int length = 0;
                            while ( set.contains( el + length ) )
                                length++;
                            return length;
                        };
    auto counts = set   | std::views::filter(comparatorFn)
                        | std::views::transform(transformToCountFn)
                        | std::ranges::to<std::vector>();

    return std::ranges::max(counts);
}


предлагаю затестить

safocl ★★
()
Ответ на: комментарий от former_anonymous

это же асимптотическая сложность — не отражающая относительность реальной скорости — O(1) может занимать больше времени чем O(n) в каких то примерах.

safocl ★★
()
Ответ на: комментарий от anonymous

std::unordered_set<Key,Hash,KeyEqual,Allocator>::erase

References and iterators to the erased elements are invalidated. Other iterators and references are not invalidated.

и https://eel.is/c draft/stmt.ranged#1
иными словами короче — это UB

safocl ★★
()
Последнее исправление: safocl (всего исправлений: 1)
Ответ на: комментарий от anonymous

тут даже не с range-based-for-loop UB — модифицируется контейнер, по которому итерация идёт, и инвалидируется как минимум итератор, по которому эрейзится.

safocl ★★
()
Ответ на: комментарий от anonymous

Инициализировать надо уникальными значениями, union-find - это лес непересекающихся множеств, по началу единичных множеств из уникальных элементов. Также придется создать map числа на элемент-ноду union-find, возможно также обратный map. И всё это - не линейная сложность

во-первых линейная при условии нормальной реализации хэш-таблицы и/или валидации входных данных. Во-вторых это задача для собеседования, придуманная специально для того чтобы проверить твои знания в нескольких вопросах и поставить не просто «решил/не решил», а более детальный грейд.

Т.е. типичный сценарий собеседования - кандидат реализует что-то с помощью сортировки, если там не ошибок - то у него спрашивают «а можешь придумать алгоритм быстрее», если он не додумывается до системы непересекающихся множеств - то ему попытаются повысить грейд вопросами про хэш-таблицы.

Если ты правильно реализовываешь СНМ, то получаешь оффер программистом в гугл; если нет, но справляешься с сортировкой и отлично рассказываешь про хэш-таблицы - то тебе могут попытаться подобрать другую позицию (например SRE вместо SWE); во всех остальных случаях - отказ.

По крайней мере так было до ковида. Сейчас все наверняка сложнее, а если ты из России, то думаю вообще не пригласят на собес))

Lrrr ★★★★★
()
Ответ на: комментарий от Lrrr

лишь однажды вопрос — накой это на собесе вообще спрашивать для реализации, если таковое уже придумано очень давно и реализации уже имеются? — бессмысленное — просто юзаешь в коде то что уже сделано, зачем самому что-то таковое делать? — вот и вырастают поколения разрабов-костылеровщиков, которые делают явные циклы в коде вместо уже имеющихся готовых решений.

лучше бы исследовали знания в части использования памяти, кастов, юнионов и подобного, что как раз может сделать качественную оценку для того, как может тот или иной разработчик сделать код, — поскольку в случае незнания (непонимания) такового и происходят все эти «запинки» с багами в коде, которые очень сложно отследить (хотя бывает и достаточно тривиально, если нормально поиском по кодовой базе пройтись по очевидным сценариям частых ошибок).

ну и лично моё мнение — что попросту наоборот на счёт использования явных «реализаций» в коде нужно «ругать», что бы использовали уже написанное — иначе кодовые базы вот и превращаются в многомиллионные строки вместо использования до сотен раз меньшего количества.

все эти «олимпиадовские» «замашки» должны пресекаться на отборе — ну и во время отслеживания возделанного кода тимлидами. — А тут я порой читаю что как раз «тимлид-подобные» лица наоборот поощрают написание «встроенного явного цикла», вместо использования уже готового алгоритма. Да и даже на олимпиадах я считаю необходимо снижать оценки сильно для неспособных применять уже имеющийся код (как минимум в стандартной либе).

safocl ★★
()
Последнее исправление: safocl (всего исправлений: 4)