Как лучше всего проверить сортировку std::vector? Есть ли что-то более быстрое, чем циклическая проверка этого v[i]<=v[i+1]? Это быстрее / чище с итераторами? Или на самом деле лучше каждый раз просто вызывать sort (хотя случай «v уже отсортирован» довольно распространен)?
Мы можем с уверенностью предположить, что вектор содержит только POD, обычно float, а иногда и double и int.
Размер вектора нетривиален (обычно несколько тысяч элементов), но не экстремален (не гигабайт).





Is there something faster than a loop checking that v[i]<=v[i+1] ?
Нет.
Если это то, что вы хотите часто проверять, вы можете создать класс-оболочку, в котором будет храниться «отсортированный» флаг, который начинается с False, устанавливается в False всякий раз, когда добавляется элемент, и добавить функцию-член sort (), которая устанавливает после сортировки флаг установлен на True.
Это хорошая идея ! И мы это уже делаем по возможности :). Но в данном случае мы застряли на хорошем ole vanillay std :: vector ...
О, хорошо ... вот что пришло мне в голову, когда я увидел вопрос ... рад, что я, кажется, подумал правильно.
Is there something faster than a loop checking that v[i]<=v[i+1] ?
Вам нужно будет проверить любое значение, чтобы увидеть, отсортировано ли оно, чтобы оно не ускорилось, чем O (n), если вы сами не отслеживаете изменения при изменении вектора или не используете уже отсортированную структуру данных.
Or is it actually better to just call sort every time (though the "v is already sorted" case is quite common) ?
Помните, что худшее поведение быстрой сортировки происходит, когда список уже отсортирован (и точка поворота выбрана неправильно). Чтобы избежать такого поведения, вы можете попробовать std :: stable_sort в качестве замены.
std::sort, как правило, не является наивной быстрой сортировкой.
Чтобы проверить сортировку, вы должны проверить каждый элемент. Таким образом, v [i] <= v [i + 1] - самая быстрая из возможных проверок.
Вам не нужно проверять каждый элемент, просто проверяйте, пока не найдете несортированный элемент :)
Is there something faster than a loop checking that v[i]<=v[i+1] ?
Нет.
Однако, если вы собираетесь выполнить проверку, чтобы решить, сортировать ли вектор, вам может быть лучше просто всегда сортировать если, вы используете правильный алгоритм сортировки, то есть std :: stable_sort, а не std :: sort.
Хммм ... Что касается POD, я не верю, что stable_sort принесет что-нибудь по сравнению с интросортом (используемым std :: sort).
@rlerallut: конкретный алгоритм зависит от реализации библиотеки.
Вы также можете выполнить сортировку вставкой с лучшим случаем O (n), когда список уже отсортирован. Если вы превысили определенное количество свопов, откажитесь от этого и просто выполните быструю сортировку.
Лучше всего использовать std::is_sorted:
is_sorted(v.begin(), v.end())
:-)
Это расширение SGI. У меня это с GCC, но не с VC++ 7. Правда, это всего лишь копипаст! В любом случае, мне придется сравнить его подход, основанный на итераторах, с подходом на основе индекса ... Тогда мы сможем сказать, что это «лучший способ». :)
В C++ 11 теперь тоже есть is_sorted
Конечно, я ничего не знаю о вашей проблемной области, поэтому, пожалуйста, не обращайте на меня внимания, если то, что я говорю, не имеет отношения к делу, но мне кажется, что если я требую, чтобы коллекция всегда сортировалась при каждом обращении к ней, естественно несортированная коллекция, такая как vector<T> может быть не лучшим выбором.
Устаревшие форматы, а также сжатие данных. Кроме того, как только сортировка завершена (а это не который длинная часть процесса), доступ к вектору становится очень быстрым! Но я приветствую ваш образ мышления: «Решаю ли я правильную проблему?».
Как отмечали другие, предикатом для определения отсортированного состояния является O (n). Но из-за вашего упоминания о сортированном флаге я задаюсь вопросом, не нужно ли вам что-то вроде этого:
Базовые библиотеки нашего приложения включают в себя класс контейнера, членство в котором можно запросить. Вот краткий набросок:
class ObjList {
public:
ObjList() {};
~ObjList() {};
bool isMember(const Item *);
void add(const Item *, bool sort = false);
private:
unsigned int last_sorted_d;
bool sorted_d;
unsigned int count_d;
Item *store_d;
};
isMember () использует двоичный поиск по отсортированный диапазон элементов, а затем линейный поиск элементов после отсортированного диапазона. Вставка может запускать сортировку элементов или нет, по выбору программиста. Например, если вы знаете, что будете добавлять тысячи элементов в плотный цикл, не выполняйте сортировку до окончательной вставки.
Это всего лишь набросок, а хранилище сложнее, чем массив указателей, но идею вы поняли.
Если вы ожидаете, что список будет очень близок к отсортированному, может быть полезно попробовать модификацию вставка сортировки. Если список уже отсортирован, он просто выполняет один проход и сообщает вам об этом. Если список почти отсортирован, он будет отсортирован очень быстро. Если список не отсортирован, прервите сортировку после некоторого количества обменов и переключитесь на быструю сортировку (или stable_sort).
Рассмотрим несколько ядер ЦП
Это зависит от вашей платформы и количества элементов в векторе. Вам нужно будет провести тест, чтобы найти лучшее.
Невозможно ответить: есть ли что-то более быстрое, чем цикл, проверяющий, что v [i] <= v [i + 1]?
С: Нет.
Потому что ... в наши дни компьютеры имеют несколько процессоров / ядер / гиперпоточность. Таким образом, может быть намного быстрее использовать параллелизм в компьютере, разделив работу по проверке на несколько потоков, так что каждый процессор может параллельно проверять небольшой диапазон.
Вероятно, лучше сделать это через библиотечную функцию, чем реализовывать ее самостоятельно. В новых версиях библиотек используется парализм. Итак, если вы выберете std :: sort, вы, вероятно, обнаружите, что при построении с использованием более новых реализаций STL они будут выполнять операцию параллельно за вас, и вам не нужно об этом беспокоиться. Я не знаю, есть ли готовые версии STL, которые уже делают это, но стоит придерживаться функций библиотеки, чтобы при обновлении до версии, которая делает это, эта оптимизация была для вас без необходимости вносить какие-либо изменения. .
+1 проницательный. К сожалению, моя реализация is_sorted (которая шла с довольно старой версией gcc (3.4.x) ужасно проста). Кроме того, разве пропускная способность памяти не является ограничивающим фактором для такого простого цикла?
Сложно сказать, будет ли ограничиваться пропускная способность памяти. Все зависит от вашей платформы, размера вектора, размера элемента в векторе, времени, затраченного на сравнение, и т. д. Вот почему требуется время / сравнительный анализ, если вы хотите узнать, как выжать каждую унцию сока.
Если при вставке элементов вы используете двоичный поиск, чтобы найти точку вставки, то он никогда не упорядочивается.
std::adjacent_find(v.begin(), v.end(), std::greater<type>()) == v.end()
Если ваша реализация стандартной библиотеки C++ содержит алгоритм is_sorted (), это лучший вариант.
C++ - 11 содержит is_sorted в <algorithm>.
Вы сортируете сразу, если не сортируете? Это может иметь какое-то значение.