Возникает важный вопрос — что делают эти алгоритмы для элементов с одинаковыми значениями атрибута? Предположим, вектор содержит 12 элементов с рангом 1 и 15 элементов с рангом 2. В этом случае выборка 20 «лучших» объектов Widget
будет состоять из 12 объектов с рангом 1 и 8 из 15 объектов с рангом 2. Но как алгоритмы partial_sort
и nth_element
определяют, какие из 15 объектов следует отобрать в «верхнюю двадцатку»? И как алгоритм sort
выбирает относительный порядок размещения элементов при совпадении рангов?
Алгоритмы partial_sort
и nth_element
упорядочивают эквивалентные элементы по своему усмотрению, и сделать с этим ничего нельзя (понятие эквивалентности рассматривается в совете 19). Когда в приведенном примере возникает задача заполнения объектами Widget
с рангом 2 восьми последних позиций в «верхней двадцатке», алгоритм выберет такие объекты, какие сочтет нужным. Впрочем, такое поведение вполне разумно. Если вы запрашиваете 20 «лучших» объектов Widget
, а некоторых объекты равны, то в результате возвращенные объекты будут по крайней мере «не хуже» тех, которые возвращены не были.
Полноценная сортировка обладает несколько большими возможностями. Некоторые алгоритмы сортировки Widget
A предшествует Widget
B в несортированном векторе widgets
и при этом ранги двух объектов совпадают, стабильный алгоритм сортировки гарантирует, что после сортировки Widget
A по-прежнему будет предшествовать Widget
B. Нестабильный алгоритм такой гарантии не дает.
Алгоритм partial_sort
, как и алгоритм nth_element
, стабильным не является. Алгоритм sort
также не обладает свойством стабильности, но существует специальный алгоритм stable_sort
, который, как следует из его названия, является стабильным. При необходимости выполнить стабильную сортировку, вероятно, следует воспользоваться stable_sort
. В STL не входят стабильные версии partial_sort
и nth_element
.
Следует заметить, что алгоритм nth_element чрезвычайно универсален. Помимо выделения n
верхних элементов в интервале, он также может использоваться для вычисления медианы по интервалу и поиска значения конкретного
vector
vector
// итераторов widgets
vector
// интересующий нас объект Widget
// Следующий фрагмент находит Widget с рангом median
goalPosition = begin + widgets.size/2; // Нужный объект находится
// в середине отсортированного вектора
nth_element(begin, goalPosition, end, // Найти ранг median в widgets
qualityCompare);
… // goalPositon теперь указывает
// на Widget с рангом median
// Следующий фрагмент находит Widget с уровнем 75 процентилей
vector
0.25*widgets.size; // объекта Widget от начала
nth_element(begin, egin+goalOffset, nd, // Найти ранг в
ualityCompare); // begin+goalOffset теперь
… // указывает на Widget
// с уровнем 75 процентилей
Алгоритмы sort
, stable_sort
и partial_sort
хорошо подходят для упорядочивания результатов сортировки, а алгоритм nth_element
решает задачу идентификации верхних n
элементов или элемента, находящегося в заданной позиции. Иногда возникает задача, близкая к алгоритму nth_element
, но несколько отличающаяся от него. Предположим, вместо 20 объектов Widget
с максимальным рангом потребовалось выделить все объекты Widget
с рангом 1 или 2. Конечно, можно отсортировать вектор по рангу и затем найти первый элемент с рангом, большим 2. Найденный элемент определяет начало интервала с объектами Widget
, ранг которых превышает 2.