Поиск «новых» элементов из двух контейнеров

#c #algorithm #boost #stl

#c #алгоритм #повышение #stl

Вопрос:

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

Под дублированием / новым я подразумеваю следующее: Контейнер 1 содержит: [1, 2, 4, 8, 16] Контейнер 2 содержит: [1, 2, 4, 16, 32]

После запуска алгоритма новый контейнер (или модифицированный контейнер 2) должен содержать: Контейнер 3 содержит: [32]

Обратите внимание, что я не хочу, чтобы «8» было в новом контейнере (или измененном контейнере), поскольку я хочу только найти «новые» значения.

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

Итак… Какой был бы «лучший» (читай: самый элегантный и эффективный) способ сделать это?

Заранее спасибо.

P.S. Если это вообще уместно, я использую это, чтобы написать инструмент ‘diffing’ для экспортированных функций из библиотеки DLL. У меня есть несколько очень больших библиотек DLL, и я хочу найти «новые» экспортированные файлы в последних сборках этих библиотек DLL.

Ответ №1:

Похоже, STL set_difference может подойти вам. Пример из здесь:

 // set_difference example
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main () {
  int first[] = {5,10,15,20,25};
  int second[] = {50,40,30,20,10};
  vector<int> v(10);                           // 0  0  0  0  0  0  0  0  0  0
  vector<int>::iterator it;

  sort (first,first 5);     //  5 10 15 20 25
  sort (second,second 5);   // 10 20 30 40 50

  it=set_difference (first, first 5, second, second 5, v.begin());
                                               // 5 15 25  0  0  0  0  0  0  0

  cout << "difference has " << int(it - v.begin()) << " elements.n";

  return 0;
}
  

Комментарии:

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

2. Вы полностью правы, мой STL немного заржавел, это моя ошибка. Я изменил ответ, надеюсь, на этот раз я все понял правильно =)

3. set_difference — это алгоритм, которого мне не хватало. Спасибо!

4. set_difference это алгоритм, но здесь, чтобы достичь того, чего хотел OP, нам нужно изменить порядок передаваемых контейнеров. Вместо этого должно быть it=set_difference (second, second 5, first, first 5, v.begin()); . Notice that I do NOT want '8' to be in the new container (or modified container) as I only want to find the 'new' values.

Ответ №2:

Самым простым методом, вероятно, была бы сортировка с последующим повторением. Поскольку оба контейнера отсортированы, вы можете просто напрямую сравнить каждый индекс (или итератор без ссылок) на предмет равенства и вставить в новый (или удалить из существующего), только если они не равны. Это O (n logn) и зависит от operator< и operator== .

Комментарии:

1. Вопрос разрешает выбор отсортированных входных контейнеров, поэтому с учетом предварительно отсортированных входных данных это всего лишь O (max (M, N)) — M и N — количество элементов в каждом из входных контейнеров….

Ответ №3:

hash_table в STL может решить эту проблему.

  1. Вставьте все элементы из первого контейнера в hash_table.
  2. Для каждого элемента в контейнере номер два проверьте, есть ли он в hash_table или нет; если нет, поместите его в контейнер номер три.

Общая временная сложность составляет O (n). Метод сортировки и сравнения имеет временную сложность O(nlogn).