Эффективный способ вставки данных в отсортированный вектор

Имея отсортированный std::vector, вставку элемента по порядку можно выполнить с помощью этого кода.

После вставки одного элемента мне нужно отсортировать вектор для обработки.

template< typename T >
typename std::vector<T>::iterator 
   insert_sorted( std::vector<T> & vec, T const& item )
{
    return vec.insert
        ( 
            std::upper_bound( vec.begin(), vec.end(), item ),
            item 
        );
}

Этот код не очень эффективен по сравнению с вызовом emplace_back.

Есть ли лучшая реализация для вставки данных в отсортированный вектор, возможно, с использованием std::rotate, чтобы избежать перераспределения/перехода данных

NB. Я не сравниваю две вставки, а просто чтобы иметь представление о номинальном случае (т. е. вставке упорядоченных чисел).

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

Botje 14.03.2024 10:54

Отвечает ли это на ваш вопрос? как вставить значение в отсортированный вектор?

ouuan 14.03.2024 10:55

У вопроса проблема XY. Не существует более быстрого способа вставки элементов в вектор. Простая вставка элемента в середину вектора имеет временную сложность O(n) (n — размер вектора). Правильный способ решить вашу проблему — перепроектировать алгоритм или структуру данных, но в вопросе нет информации об этом.

Marek R 14.03.2024 11:08

Вы должны понимать свои данные и то, какие операции вам нужны больше всего. А затем вы выбираете (или проектируете) соответствующую структуру данных. Итак, объясните немного больше о размере ваших данных, о том, как часто вы собираетесь добавлять данные, ожидаете ли вы, что локальность данных важна (кэши/непрерывная память) и т. д. Примечание: может быть даже быстрее вставлять элементы в назад, а затем вызвать сортировку O(log n). В частности, если вы собираетесь вставлять значения пакетами.

Pepijn Kramer 14.03.2024 11:12

Если производительность вставки имеет решающее значение, вам нужно будет использовать другую структуру данных, например std::set, но вам нужно будет протестировать свое приложение, чтобы убедиться, что оно не окажется более дорогим в другом месте.

Alan Birtles 14.03.2024 11:19

Да, я провел тест, и std::vector более эффективен, чем std::set.

Ted Zach 14.03.2024 11:20

Вы снова задаете неправильный вопрос. Вы должны описать проблему, в которой вы используете этот отсортированный вектор.

Marek R 14.03.2024 11:23

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

Galik 14.03.2024 11:28

«Да, я провел тест, и std::vector более эффективен, чем std::set», это зависит от размера контейнера. Ожидается, что для небольших размеров вектор будет быстрым, но есть поворотный момент, после которого вставка в std::set происходит быстрее.

463035818_is_not_an_ai 14.03.2024 11:48

Естественно, показанный вами подход менее эффективен, чем emplace_back() .... потому что emplace_back() не гарантирует, что вектор будет отсортирован по завершении. Итак, ваше утверждение сравнивает яблоко с апельсином. Чтобы сделать сравнение с emplace_back() более справедливым, вам нужно отсортировать вектор, например, после vec.emplace_back(item); std::sort(vec.begin(), vec.end());

Peter 14.03.2024 11:52

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

463035818_is_not_an_ai 14.03.2024 11:52

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

463035818_is_not_an_ai 14.03.2024 11:52

@ 463035818_is_not_an_ai, я обработал вектор сразу после вставки (перед обработкой вектор необходимо отсортировать)

Ted Zach 14.03.2024 12:02

Вы имеете в виду, что после вставки одного элемента вам необходимо отсортировать вектор? Пожалуйста, уточните это в вопросе.

463035818_is_not_an_ai 14.03.2024 12:44
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
14
167
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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

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

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

Например, если вы ожидаете, что большинство элементов будут вставлены сзади, вы можете просто сначала проверить этот случай и вставить в конце.

template< typename T >
typename std::vector<T>::iterator 
   insert_sorted_expect_greatest( std::vector<T> & vec, T const& item )
{
    typename std::vector<T>::iterator where = item > vec.back() ? vec.end() : std::upper_bound( vec.begin(), vec.end(), item );

    return vec.insert( where, item );
}

Я исправил вопрос. NB. Я не сравниваю две вставки, а просто чтобы иметь представление о номинальном случае (т. е. вставке упорядоченных чисел).

Ted Zach 14.03.2024 11:22

@TedZach какую операцию ты на самом деле хочешь?

Caleth 14.03.2024 11:26

Мне нужно вставить, сохраняя заказ. 90% новый элемент больше предыдущего вставленного

Ted Zach 14.03.2024 11:53

Прошу прощения. Все вставленные элементы

Ted Zach 14.03.2024 11:59

@больше, чем последний вставленный элемент, или больше, чем все элементы? Вы вставляете по одному или можете вставить диапазон?

Caleth 14.03.2024 11:59

Я вставляю по одному элементу за раз. И обработать вектор после вставки

Ted Zach 14.03.2024 12:00

Тогда вам не нужно вставлять в отсортированный вектор. Вы можете вставить в вектор и отсортировать позже.

Caleth 14.03.2024 12:05

Значит, вставка с помощью двоичного поиска хуже, чем emplace_back + sort?

Ted Zach 14.03.2024 12:07

@TedZach за некоторое количество вставок

Caleth 14.03.2024 12:13

Почему бы и нет, если в порядке [[вероятно]] emplace_back else emplace_back + sort ?

Ted Zach 14.03.2024 12:15

Ой, я неправильно прочитал требование. Если вам нужно обрабатывать vec после каждой вставки, то emplace_back+sort, вероятно, будет хуже, чем search+insert. Но для ваших реальных данных вы можете не увидеть большой разницы.

Caleth 14.03.2024 12:18

Попробую с помощью QuickBench, посмотрим результат

Ted Zach 14.03.2024 12:24

Вы можете получить почти такой же результат, используя амортизированный анализ. У вас есть всеобъемлющая структура данных, содержащая вектор. Вы помещаете_back или emplace_back в вектор и притворяетесь, что это отсортированная вставка, хотя это не так. Вы записываете внутри себя наличие новых (неотсортированных) записей.

Затем, когда в следующий раз кто-то получит доступ к данным, вы все это сортируете. std::sort действительно хорош для смежных данных. Если у вас есть много отсортированных вставок перед следующим доступом, это работает очень хорошо. И аналитически, и практически.

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

Marek R 14.03.2024 11:43

@MarekR Вероятно, именно поэтому я прямо заявил, в чем заключается предостережение и явное предположение? Думаете, это недостаточно ясно?

bitmask 14.03.2024 12:23

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