Объедините 2 вектора STL за постоянное время O (1)

Я дам некоторый контекст того, почему я пытаюсь это сделать, но в конечном итоге контекст можно игнорировать, поскольку это в значительной степени классическая проблема компьютерных наук и C ++ (которую наверняка задавали раньше, но пара беглых поисков ничего не обнаружил ...)

Я работаю с (большими) облаками точек потоковой передачи в реальном времени, и у меня есть случай, когда мне нужно взять 2/3/4 облака точек с нескольких датчиков и соединить их вместе, чтобы создать одно большое облако точек. Я нахожусь в ситуации, когда мне действительно нужны все данные в одной структуре, тогда как обычно, когда люди просто визуализируют облака точек, они могут уйти, передав их в средство просмотра по отдельности.

Я использую Point Cloud Library 1.6, и при ближайшем рассмотрении ее Класс PointCloud (под <pcl/point_cloud.h>, если вам интересно) хранит все точки данных в векторе STL.

Теперь мы вернулись на землю ванильной CS ...

В PointCloud есть оператор + = для добавления содержимого одного облака точек в другое. Все идет нормально. Но этот метод довольно неэффективен - если я правильно понимаю, он 1) изменяет размер целевого вектора, затем 2) проходит через все точки в другом векторе и копирует их.

Мне это выглядит как случай временной сложности O (n), что обычно может быть не так уж плохо, но является плохой новостью при работе с как минимум 300K точек на облако в реальном времени.

Векторы не нужно сортировать или анализировать, их просто нужно «склеить» на уровне памяти, чтобы программа знала, что как только она достигает конца первого вектора, ей просто нужно перейти в начальную точку второй. Другими словами, я ищу метод слияния векторов O (1). Есть ли способ сделать это в STL? Или это скорее домен чего-то вроде std :: list # splice?

Примечание. Этот курс является фундаментальной частью PCL, поэтому предпочтительнее «неинвазивная хирургия». Если необходимо внести изменения в сам класс (например, переход от вектора к списку или резервирование памяти), их следует рассматривать с точки зрения воздействия на остальную часть PCL, которое может иметь далеко идущие последствия.

Обновление: я зарегистрировал проблему в репозитории PCL на GitHub, чтобы обсудить с авторами библиотеки приведенные ниже предложения. Как только появится какое-то решение, к которому следует подходить, я приму соответствующие предложения в качестве ответов.


person chriskilding    schedule 25.07.2013    source источник
comment
Насколько я знаю, это невозможно. Почему бы вам не зарезервировать свой вектор для большой емкости, которая вам удобна?   -  person Rapptz    schedule 25.07.2013
comment
Я знаю C ++, C и C #. Но что такое CS?   -  person Daniel S.    schedule 25.07.2013
comment
Я думаю, ОП означает компьютерные науки.   -  person Useless    schedule 25.07.2013
comment
@ user1475135: векторы редко меняют размер, даже с +=. Если это действительно std::vector, не беспокойтесь об этом, это не ваша проблема.   -  person Mooing Duck    schedule 25.07.2013
comment
потенциально возможно неинвазивно зарезервировать память, просто отодвинув N точку при ее создании, а затем удалив их все.   -  person Mooing Duck    schedule 25.07.2013
comment
Возможно ли для вас в первую очередь убедить ваши несколько источников для всех точек сброса в один вектор?   -  person Casey    schedule 25.07.2013


Ответы (7)


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

person David Rodríguez - dribeas    schedule 25.07.2013

Эта проблема решалась много раз раньше, например, с классами String Rope.

Базовый подход - создать новый тип контейнера, в котором будут храниться указатели на облака точек. Это похоже на std :: deque, за исключением того, что у вас будут куски переменного размера. Разве ваши облака разбиваются на стандартные размеры?

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

person Zan Lynx    schedule 25.07.2013

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

Также нет способа конкатенации векторов с постоянным временем.

Я могу придумать один (хрупкий) способ объединить необработанные массивы за постоянное время, но это зависит от того, будут ли они выровнены по границам страницы как в начале, так и в конце, а затем повторно сопоставить их, чтобы они были соседний. Это будет довольно сложно обобщить.

Есть другой способ сделать что-то, что похоже на конкатенированный вектор, и это с помощью контейнера-оболочки, который работает как двухсторонняя очередь и предоставляет унифицированный итератор и operator[] над ними. Однако я не знаю, достаточно ли гибкая библиотека облаков точек для работы с этим. (Предложение Джамина состоит в том, чтобы использовать что-то вроде этого вместо вектора, а Zan примерно то, что я имел в виду).

person Useless    schedule 25.07.2013

Нет, вы не можете соединить два вектора простой связью, вам действительно нужно их скопировать.

Тем не мение! Если вы реализуете семантику перемещения в своем типе элемента, вы, вероятно, получите значительный прирост скорости в зависимости от того, что содержит ваш элемент. Это не поможет, если ваши элементы не содержат нетривиальных типов. Кроме того, если у вас есть резервный вектор заранее необходимой памяти, это также поможет ускорить процесс, не требуя изменения размера (что приведет к нежелательному огромному новому распределению, возможно, к необходимости дефрагментации при этом размере памяти, а затем огромный memcpy).

За исключением этого, вы можете захотеть создать какое-то сочетание между связанными списками и векторами, где каждый `` элемент '' списка является вектором с 10 тыс. Элементов, поэтому вам нужно переходить по ссылкам списка только один раз через каждые 10 тыс. Элементов, но это позволяет вам будет намного проще динамически расти и сделать вашу конкатенацию легкой.

std::list<std::vector<element>> forIllustrationOnly; //Just roll your own custom type.

index = 52403;

listIndex = index % 1000
vectorIndex = index / 1000

forIllustrationOnly[listIndex][vectorIndex] = still fairly fast lookups
forIllustrationOnly[listIndex].push_back(vector-of-points) = much faster appending and removing of blocks of points.
person Jamin Grey    schedule 25.07.2013

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

Я не знаю PointCloud, но если вы можете использовать другие типы списков, например связанный список, такое поведение вполне возможно. Вы можете найти реализацию связанного списка, которая работает в вашей среде и может просто прикрепить второй список к концу первого списка, как вы себе представляли.

person Daniel S.    schedule 25.07.2013

Взгляните на соединение диапазона Boost по адресу http://www.boost.org/doc/libs/1_54_0/libs/range/doc/html/range/reference/utilities/join.html

Это займет 2 диапазона и присоединится к ним. Скажем, у вас есть vector1 и vector 2.

Вы должны уметь писать

auto combined = join(vector1,vector2).

Затем вы можете использовать в сочетании с алгоритмами и т. Д. По мере необходимости.

person John Bandela    schedule 25.07.2013

Никакой копии O (1) для вектора никогда, но вы должны проверить:

  • Тип элемента легко копируется? (он же memcpy)
  • Мф, моя реализация vector использует этот факт, или она тупо перебирает все 300 тыс. Элементов, выполняя тривиальное присваивание (или, что еще хуже, вызов copy-ctor) для каждого элемента?

Я заметил, что, хотя и memcpy, и назначение цикла имеют сложность O (n), решение, использующее memcpy, может быть намного, намного быстрее.

Итак, проблема может заключаться в том, что реализация вектора неоптимальна для тривиальных типов.

person Martin Ba    schedule 26.07.2013