Если данные уже находятся в массиве, который вы можете изменить, вы можете использовать вариант алгоритма выбора Хоара, который (в свою очередь) является вариантом быстрой сортировки.
Основная идея довольно проста. В Quicksort вы разбиваете массив на две части, один из которых больше, чем сводная, а другой - меньше, чем сводная. Затем вы рекурсивно сортируете каждый раздел.
В алгоритме выбора вы выполняете шаг разделения точно так же, как и раньше - но вместо рекурсивной сортировки обоих разделов вы смотрите, какой раздел содержит нужные вам элементы, и рекурсивно выбираете ТОЛЬКО в этом разделе , Например, при условии, что ваш 100 миллионов элементов разделен почти пополам, на первых нескольких итерациях вы будете смотреть только на верхний раздел.
В конце концов, вы, вероятно, достигнете точки, в которой нужная вам часть «соединяет» два раздела - например, у вас есть раздел из ~ 150 чисел, а когда вы разбиваете, у вас получается два фрагмента из ~ 75 кусочек. В этот момент изменяется только одна незначительная деталь: вместо отклонения одного раздела и продолжения работы только с другим, вы принимаете верхний раздел из 75 элементов, а затем продолжаете искать верхние 25 в нижнем разделе.
Если вы делали это в C ++, вы могли бы сделать это с std::nth_element
(который обычно будет реализован примерно так, как описано выше). В среднем, это имеет линейную сложность, которая, я считаю, примерно так же хороша, как вы можете надеяться (без какого-либо существовавшего ранее порядка я не вижу способа найти верхние N элементов, не глядя на все элементы).
Если данные не уже находятся в массиве, и вы (например) читаете данные из файла, вы обычно хотите использовать кучу. Вы в основном читаете элемент, вставляете его в кучу, и если куча больше, чем вы планируете (в данном случае 100 элементов), вы удаляете один элемент и заново создаете кучу.
Что, вероятно, не так очевидно (но на самом деле верно), что вы обычно не хотите использовать max-heap для этой задачи. На первый взгляд, кажется довольно очевидным: если вы хотите получить максимальное количество предметов, вы должны использовать максимальную кучу.
Однако проще думать о предметах, которые вы «удаляете» из кучи. Максимальная куча позволяет быстро найти один из крупнейших элементов в куче. Однако он не оптимизирован для поиска самого маленького элемента в куче.
В данном случае нас интересует, прежде всего, наименьший элемент в куче. В частности, когда мы читаем каждый элемент из файла, мы хотим сравнить его с наименьшим элементом в куче. Если (и только если) он больше, чем самый маленький элемент в куче, мы хотим заменить этот самый маленький элемент, находящийся в данный момент в куче, на новый элемент. Так как это (по определению) больше, чем существующий элемент, нам нужно будет просеять его в правильной позиции в куче.
Но обратите внимание: если элементы в файле упорядочены случайным образом, когда мы читаем файл, мы довольно быстро достигаем точки, в которой большинство элементов, которые мы читаем в файл, будут меньше, чем самые маленькие предмет в нашей куче. Поскольку у нас есть легкий доступ к наименьшему элементу в куче, это сравнение выполняется довольно быстро и легко, а для более мелких элементов он вообще не вставляется в кучу.