Учитывая два списка (не обязательно отсортированные), каков наиболее эффективный нерекурсивный алгоритм для поиска пересечения этих списков?
Эффективный алгоритм пересечения списков
Ответ 1
Вы можете поместить все элементы первого списка в хэш-набор. Затем повторите итерацию второго, и для каждого из его элементов проверьте хэш, чтобы увидеть, существует ли он в первом списке. Если это так, выведите его как элемент пересечения.
Ответ 2
Возможно, вы захотите взглянуть на фильтры Bloom. Это битовые векторы, которые дают вероятностный ответ, является ли элемент членом набора. Установить пересечение может быть реализовано с помощью простой побитовой операции И. Если у вас большое количество нулевых пересечений, фильтр Bloom может помочь вам быстро их устранить. Однако вам все равно придется прибегнуть к одному из других алгоритмов, упомянутых здесь, для вычисления фактического пересечения. http://en.wikipedia.org/wiki/Bloom_filter
Ответ 3
без хеширования, я полагаю, у вас есть два варианта:
- Наивный способ заключается в сравнении каждого элемента с каждым другим элементом. O (N ^ 2)
- Другим способом было бы сначала отсортировать списки, затем перебрать их: O (n lg n) * 2 + 2 * O (n)
Ответ 4
Из списка функций eviews кажется, что он поддерживает сложные слияния и объединения (если это "соединение", как в терминологии БД, оно будет вычислить пересечение). Теперь просмотрите свою документацию: -)
Кроме того, eviews имеет свой собственный форум пользователей - почему бы не спросить там _
Ответ 5
с помощью набора 1 постройте двоичное дерево поиска с O(log n)
и выполните итерацию set2 и выполните поиск BST m X O(log n)
, так что итого O(log n) + O(m)+O(log n) ==> O(log n)(m+1)
Ответ 6
в С++ можно попробовать следующее: STL map
vector<int> set_intersection(vector<int> s1, vector<int> s2){
vector<int> ret;
map<int, bool> store;
for(int i=0; i < s1.size(); i++){
store[s1[i]] = true;
}
for(int i=0; i < s2.size(); i++){
if(store[s2[i]] == true) ret.push_back(s2[i]);
}
return ret;
}
Ответ 7
Вот еще одно возможное решение, с которым я столкнулся, принимает O (nlogn) во временной сложности и без какого-либо дополнительного хранилища. Вы можете проверить это здесь https://gist.github.com/4455373
Вот как это работает. Предполагая, что наборы не содержат повторений, объедините все наборы в один и отсортируйте. Затем пропустите объединенный набор и на каждой итерации создайте подмножество между текущим индексом я и я + n, где n - количество наборов, доступных во юниверсе. То, что мы ищем в качестве цикла, представляет собой повторяющуюся последовательность размера n, равную числу множеств в юниверсе.
Если это подмножество в я равно этому подмножеству в n, это означает, что элемент at я повторяется n раз, что равно общему числу множеств. И поскольку в любом наборе нет повторений, что означает, что каждый из наборов содержит это значение, поэтому мы добавляем его к пересечению. Затем мы сдвигаем индекс на я + то, что осталось между ним и n, потому что определенно ни один из этих индексов не собирается формировать повторяющуюся последовательность.
Ответ 8
Сначала сортируйте оба списка с помощью quicksort: O (n * log (n). Затем сравните списки, просмотрев самые младшие значения и добавьте общие значения. Например, в lua):
function findIntersection(l1, l2)
i, j = 1,1
intersect = {}
while i < #l1 and j < #l2 do
if l1[i] == l2[i] then
i, j = i + 1, j + 1
table.insert(intersect, l1[i])
else if l1[i] > l2[j] then
l1, l2 = l2, l1
i, j = j, i
else
i = i + 1
end
end
return intersect
end
который O(max(n, m))
, где n
и m
- размеры списков.
EDIT: quicksort рекурсивна, как сказано в комментариях, но похоже, что нерекурсивный реализация
Ответ 9
Почему бы не реализовать свою собственную хэш-таблицу или хеш-набор? Стоит избегать пересечения nlogn, если ваши списки велики, как вы говорите.
Поскольку вы немного знаете о своих данных, вы должны иметь возможность выбрать хорошую хэш-функцию.
Ответ 10
Если существует поддержка sets (как вы их называете в названии), как встроенный, обычно существует метод пересечения.
В любом случае, как кто-то сказал, что вы можете сделать это легко (я не буду отправлять код, кто-то уже сделал это), если у вас отсортированы списки. Если вы не можете использовать рекурсию, проблем нет. Существуют варианты быстрой сортировки без рекурсии.
Ответ 11
Во-вторых, идея "множеств". В JavaScript вы можете использовать первый список для заполнения объекта, используя элементы списка в качестве имен. Затем вы используете элементы списка из второго списка и видите, существуют ли эти свойства.
Ответ 12
У меня есть хорошие ответы от этого, которые вы можете подать. У меня пока нет возможности попробовать их, но поскольку они также охватывают пересечения, вы можете найти их полезными.
Ответ 13
В PHP что-то вроде
function intersect($X) { // X is an array of arrays; returns intersection of all the arrays
$counts = Array(); $result = Array();
foreach ($X AS $x) {
foreach ($x AS $y) { $counts[$y]++; }
}
foreach ($counts AS $x => $count) {
if ($count == count($X)) { $result[] = $x; }
}
return $result;
}
Ответ 14
Из определения обозначения Big-Oh:
T (N) = O (f (N)), если существуют положительные константы c и n 0 такие, что T (N) ≤ cf (N), когда N ≥ n 0.
Что на практике означает, что если два списка относительно малы по размеру, говорят, что менее 100 элементов в каждом из двух для циклов работают просто отлично. Завершите первый список и найдите аналогичный объект во втором. В моем случае это работает нормально, потому что у меня не будет больше 10 - 20 максимальных элементов в моих списках. Однако хорошим решением является сортировка первого O (n log n), сортировка второго также O (n log n) и объединение их, другое O (n log n), грубо говорящее O (3 n log n), скажем, что два списка имеют одинаковый размер.
Ответ 15
Используя пропустить указатели и инструкции SSE могут улучшить список эффективность пересечения.