Лучший алгоритм для проверки сортировки вектора

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

Мы можем с уверенностью предположить, что вектор содержит только POD, обычно float, а иногда и double и int.

Размер вектора нетривиален (обычно несколько тысяч элементов), но не экстремален (не гигабайт).

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

Вы сортируете сразу, если не сортируете? Это может иметь какое-то значение.

crashmstr 04.11.2008 17:27
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
18
1
13 252
13
Перейти к ответу Данный вопрос помечен как решенный

Ответы 13

Is there something faster than a loop checking that v[i]<=v[i+1] ?

Нет.

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

Это хорошая идея ! И мы это уже делаем по возможности :). Но в данном случае мы застряли на хорошем ole vanillay std :: vector ...

rlerallut 04.11.2008 18:23

О, хорошо ... вот что пришло мне в голову, когда я увидел вопрос ... рад, что я, кажется, подумал правильно.

John 04.11.2008 23:31

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, как правило, не является наивной быстрой сортировкой.
jfs 17.11.2008 02:15

Чтобы проверить сортировку, вы должны проверить каждый элемент. Таким образом, v [i] <= v [i + 1] - самая быстрая из возможных проверок.

Вам не нужно проверять каждый элемент, просто проверяйте, пока не найдете несортированный элемент :)

crashmstr 04.11.2008 17:25

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 04.11.2008 17:36

@rlerallut: конкретный алгоритм зависит от реализации библиотеки.

Jasper Bekkers 04.11.2008 18:55

Вы также можете выполнить сортировку вставкой с лучшим случаем O (n), когда список уже отсортирован. Если вы превысили определенное количество свопов, откажитесь от этого и просто выполните быструю сортировку.

Eclipse 04.11.2008 19:34

Лучше всего использовать std::is_sorted:

is_sorted(v.begin(), v.end())

:-)

Это расширение SGI. У меня это с GCC, но не с VC++ 7. Правда, это всего лишь копипаст! В любом случае, мне придется сравнить его подход, основанный на итераторах, с подходом на основе индекса ... Тогда мы сможем сказать, что это «лучший способ». :)

rlerallut 04.11.2008 18:30

В C++ 11 теперь тоже есть is_sorted

user283145 26.04.2013 21:15

Конечно, я ничего не знаю о вашей проблемной области, поэтому, пожалуйста, не обращайте на меня внимания, если то, что я говорю, не имеет отношения к делу, но мне кажется, что если я требую, чтобы коллекция всегда сортировалась при каждом обращении к ней, естественно несортированная коллекция, такая как vector<T> может быть не лучшим выбором.

Устаревшие форматы, а также сжатие данных. Кроме того, как только сортировка завершена (а это не который длинная часть процесса), доступ к вектору становится очень быстрым! Но я приветствую ваш образ мышления: «Решаю ли я правильную проблему?».

rlerallut 04.11.2008 19:09

Как отмечали другие, предикатом для определения отсортированного состояния является 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) ужасно проста). Кроме того, разве пропускная способность памяти не является ограничивающим фактором для такого простого цикла?

rlerallut 05.11.2008 12:31

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

Scott Langham 05.11.2008 15:02

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

std::adjacent_find(v.begin(), v.end(), std::greater<type>()) == v.end()

Если ваша реализация стандартной библиотеки C++ содержит алгоритм is_sorted (), это лучший вариант.

C++ - 11 содержит is_sorted в <algorithm>.

Другие вопросы по теме