Можно сделать это за линейное время, используя алгоритм выбора , который принимает O(n)
в худшем случае, а затем один раз пройдя вектор и выбрав точно те элементы, которые как минимум столь же великикак (nk) -статистическая статистика (и ведется подсчет того, сколько элементов вы взяли, так что вы берете ровно k
и не более).Однако Cppreference говорит о том, что std::nth_element
в среднем занимает линейное время, а не худший случай.Я объясню, как сделать это немного медленнее, но, вероятно, проще, используя кучи.Это решение требует времени O(max(n,k*log(k)))
в худшем случае для извлечения верхних k
элементов вектора размером n
.
. Вы начинаете с создания max-heap со всеми элементами n
, что занимает O (n) времени с std::make_heap
.
. Теперь мы хотим извлечь из этой кучи k
верхние элементы, но мы должны быть умными, когда делаем это.Если мы извлечем максимальный элемент k
раз, это будет стоить нам O(log(n))
каждый раз, то есть всего O(k*log(n))
, что не достигает нашей цели.
Вместо этого мы не будем касаться этого n-размер кучи и создать отдельную максимальную кучу, которую я называю «кучей ожидания».Эта ожидающая куча начинается только с максимального элемента в исходной куче, и для получения верхних k
элементов вы повторяете следующую процедуру k
раз: извлеките верхний элемент из ожидающей кучи и добавьте в него двух его потомков.Размер ожидающей кучи увеличивается на единицу на каждом шаге, поэтому он ограничен k
.Поскольку мы делаем k
извлечения и 2k
вставки (при условии, что вы используете двоичную кучу), это будет стоить нам не больше, чем 3*k*log(k)
.