эффективный алгоритм перестановки для нескольких списков

У меня есть переменное количество списков. Каждый содержит разное количество элементов.

Например, с четырьмя списками,

array1 = {1, 2, 3, 4};
array2 = {a, b, c};
array3 = {X};
array4 = {2.10, 3.5, 1.2, 6.2, 0.3};

Мне нужно найти все возможные кортежи, чей i-й элемент из i-го списка, например {1, a, X, 2.10}, {1, a, X, 3.5}, …

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

Любой совет? Есть ли эффективные алгоритмы (или какой-то псевдокод). Спасибо!

Некоторый псевдокод того, что я реализовал:

Рекурсивная версия:

vector<size_t> indices; // store current indices of each list except for the last one)

permuation (index, numOfLists) { // always called with permutation(0, numOfLists)
if (index == numOfLists - 1) {
for (i = first_elem_of_last_list; i <= last_elem_of_last_list; ++i) {
foreach(indices.begin(), indices.end(), printElemAtIndex());
printElemAtIndex(last_list, i);
}
}
else {
for (i = first_elem_of_ith_list; i <= last_elem_of_ith_list; ++i) {
update_indices(index, i);
permutation(index + 1, numOfLists); // recursive call
}
}
}

нерекурсивная версия:

vector<size_t> indices; // store current indices of each list except for the last one)
permutation-iterative(index, numOfLists) {
bool forward = true;
int curr = 0;

while (curr >= 0) {
if (curr < numOfLists - 1){
if (forward)
curr++;
else {
if (permutation_of_last_list_is_done) {
curr--;
}
else {
curr++;
forward = true;
}
if (curr > 0)
update_indices();
}
}
else {
// last list
for (i = first_elem_of_last_list; i <= last_elem_of_last_list; ++i) {
foreach(indices.begin(), indices.end(), printElemAtIndex());
printElemAtIndex(last_list, i);
}
curr--;
forward = false;
}
}
}

0

Решение

Есть O(l^n)1 разные такие кортежи, где l это размер списка и n количество списков

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

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


Возможный рекурсивный подход:

printAll(list<list<E>> listOfLists, list<E> sol):
if (listOfLists.isEmpty()):
print sol
return
list<E> currentList <- listOfLists.removeAndGetFirst()
for each element e in currentList:
sol.append(e)
printAll(listOfLists, sol) //recursively invoking with a "smaller" problem
sol.removeLast()
listOfLists.addFirst(currentList)

(1) Чтобы быть точным, есть l1 * l2 * ... * ln кортежи, где li — размер i-го списка. для списков равной длины он распадается на l^n,

3

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector