Первое, что приходит на ум, - это создать структуру кучи, содержащую итераторы для каждого вектора, упорядоченные по значению, на которое они в данный момент указывают. (конечно, каждая запись должна содержать конечный итератор)
Текущий элемент находится в корне кучи, и, чтобы продвинуться, вы просто либо выталкиваете его, либо увеличиваете его ключ. (последнее можно сделать, нажав, увеличивая, затем нажимая)
Я считаю, что это должно иметь асимптотическую сложность O(E log M)
, где E
- общее количество элементов, а M
- количество векторов.
Если вы действительно выталкиваете все из векторов, вы можете создать кучу указателей на свои векторы, вы можете также рассматривать их как кучи, чтобы избежать потери производительности при удалении с фронта вектора. (или вы можете сначала скопировать все в deque
s)
Объединение их всех вместе путем объединения пар одновременно имеет одинаковую асимптотическую сложность, если вы внимательно относитесь к порядку. Если вы упорядочите все векторы в полном сбалансированном двоичном дереве, а затем попарно объединитесь при переходе вверх по дереву, тогда каждый элемент будет скопирован log M
раз, что также приведет к алгоритму O(E log M)
.
Для дополнительной фактической эффективности вместо дерева вы должны многократно объединять два самых маленьких вектора, пока у вас не останется только один. (опять же, размещение указателей на векторы в куче - путь, но на этот раз упорядоченный по длине)
(действительно, вы хотите упорядочить по «стоимости копирования» вместо длины. Дополнительная вещь для оптимизации для определенных типов значений)
Если бы мне пришлось угадывать, самым быстрым способом было бы использовать вторую идею, но с N-арным слиянием вместо попарного слияния, для некоторого подходящего N (который, я предполагаю, будет либо небольшой константой, или примерно квадратный корень из числа векторов) и выполните N-арное слияние, используя первый алгоритм, приведенный выше, для одновременного перечисления содержимого N векторов.