webBG - програмисти, машинно обучение, javascript, python, php, питам, говорим, публикации

std::vector разлики

Как се определя какви са разликите между 2 вектора?

Имам vector<int> v1 и vector<int> v2;

Това, което търся, е vector<int> vDifferences, което съдържа само елементи, които са само в v1 или v2.

Има ли стандартен начин да направите това?

14.10.2011

  • std::set_difference 14.10.2011
  • Мисля, че търсите std::set_symmetric_difference 14.10.2011
  • Ако промяната на типа на v1 и v2 е опция и ви интересува само дали има елементи във всеки, обмислете използването на std::unordered_set или std::set вместо std::vector на първо място. 15.10.2011

Отговори:


1

Ето пълния и тосен отговор. Преди да може да се използва алгоритъмът set_symmetric_difference, изходните диапазони трябва да бъдат подредени:

  using namespace std; // For brevity, don't do this in your own code...

  vector<int> v1;
  vector<int> v2;

  // ... Populate v1 and v2

  // For the set_symmetric_difference algorithm to work, 
  // the source ranges must be ordered!    
  vector<int> sortedV1(v1);
  vector<int> sortedV2(v2);

  sort(sortedV1.begin(),sortedV1.end());
  sort(sortedV2.begin(),sortedV2.end());

  // Now that we have sorted ranges (i.e., containers), find the differences    
  vector<int> vDifferences;

  set_symmetric_difference(
    sortedV1.begin(),
    sortedV1.end(),
    sortedV2.begin(),
    sortedV2.end(),
    back_inserter(vDifferences));

  // ... do something with the differences

Трябва да се отбележи, че сортирането е скъпа операция (т.е. O(n log n) за общи реализации на STL). Особено в случай, че единият или двата контейнера са много големи (т.е. милиони цели числа или повече), различен алгоритъм, използващ хеш-таблици, може да бъде за предпочитане въз основа на сложността на алгоритма. Ето описание на високо ниво на този алгоритъм:

  1. Заредете всеки контейнер в хеш таблица.
  2. Ако двата контейнера се различават по размер, хеш-таблицата, съответстваща на по-малкия, ще се използва за обхождане в Стъпка 3. В противен случай ще се използва първата от двете хеш-таблици.
  3. Преминете хеш-таблицата, избрана в Стъпка 2, като проверите дали всеки елемент присъства и в двете хеш-таблици. Ако е, премахнете го и от двете. Причината, поради която по-малката хеш таблица е предпочитана за обхождане, е, че търсенията в хеш таблица са средно O(1), независимо от размера на контейнера. Следователно времето за преминаване е линейна функция на n (т.е. O(n)), където n е размерът на хеш-таблицата, която се преминава.
  4. Вземете обединението на останалите елементи в хеш-таблиците и съхранете резултата в контейнер за разлика.

C++11 ни предлага някои възможности за такова решение чрез стандартизиране на контейнера unordered_multiset. Също така използвах новото използване на ключовата дума auto за изрични инициализации, за да направя следното базирано на хеш таблица решение по-сбито:

using namespace std; // For brevity, don't do this in your own code...

// The remove_common_items function template removes some and / or all of the
// items that appear in both of the multisets that are passed to it. It uses the
// items in the first multiset as the criteria for the multi-presence test.
template <typename tVal>
void remove_common_items(unordered_multiset<tVal> &ms1, 
                         unordered_multiset<tVal> &ms2)
{
  // Go through the first hash table
  for (auto cims1=ms1.cbegin();cims1!=ms1.cend();)
  {
    // Find the current item in the second hash table
    auto cims2=ms2.find(*cims1);

    // Is it present?
    if (cims2!=ms2.end())
    {
      // If so, remove it from both hash tables
      cims1=ms1.erase(cims1);
      ms2.erase(cims2);
    }
    else // If not
      ++cims1; // Move on to the next item
  }
}

int main()
{
  vector<int> v1;
  vector<int> v2;

  // ... Populate v1 and v2

  // Create two hash tables that contain the values
  // from their respective initial containers    
  unordered_multiset<int> ms1(v1.begin(),v1.end());
  unordered_multiset<int> ms2(v2.begin(),v2.end());

  // Remove common items from both containers based on the smallest
  if (v1.size()<=v2.size)
    remove_common_items(ms1,ms2);
  else
    remove_common_items(ms2,ms1);

  // Create a vector of the union of the remaining items
  vector<int> vDifferences(ms1.begin(),ms1.end());

  vDifferences.insert(vDifferences.end(),ms2.begin(),ms2.end());

  // ... do something with the differences
}

За да се определи кое решение е по-добро за конкретна ситуация, профилирането на двата алгоритъма би било интелигентен ход на действие. Въпреки че базираното на хеш таблица решение е в O(n), то изисква повече код и върши повече работа за всеки намерен дубликат (т.е. премахване на хеш таблици). Освен това (за съжаление) използва персонализирана функция за разграничаване, а не стандартен STL алгоритъм.

Трябва да се отбележи, че и двете решения представят разликите в ред, който най-вероятно е доста различен от реда, в който елементите се появяват в оригиналните контейнери. Има начин да се заобиколи това, като се използва вариант на решението за хеш таблица. Следва описание на високо ниво (което се различава само в Стъпка 4 от предходното решение):

  1. Заредете всеки контейнер в хеш таблица.
  2. Ако двата контейнера се различават по размер, по-малката хеш-таблица ще се използва за обхождане в Стъпка 3. В противен случай ще се използва първият от двата.
  3. Преминете хеш-таблицата, избрана в Стъпка 2, като проверите дали всеки елемент присъства и в двете хеш-таблици. Ако е, премахнете го и от двете.
  4. За да формирате контейнера за разлика, обходете оригиналните контейнери по ред (т.е. първия контейнер преди втория). Потърсете всеки елемент от всеки контейнер в съответната хеш-таблица. Ако бъде намерен, елементът трябва да бъде добавен към контейнера за разлика и премахнат от неговата хеш таблица. Елементите, които не присъстват в съответните хеш-таблици, ще бъдат пропуснати. По този начин само елементите, които присъстват в хеш-таблиците, ще се окажат в контейнера за разлики и техният ред на появяване ще остане същият, както беше в оригиналните контейнери, защото тези контейнери диктуват реда на крайното преминаване.

За да се поддържа първоначалният ред, Стъпка 4 стана по-скъпа, отколкото в предишното решение, особено ако броят на премахнатите елементи е голям. Това е така, защото:

  1. Всички елементи ще бъдат тествани втори път за допустимост да се появят в контейнера за разлики чрез тест за присъствие в съответните им хеш-таблици.
  2. Хеш-таблиците ще премахнат остатъка от своите елементи един по един, когато се формира контейнерът за разлики, като част от присъстващо в разликите тестване на Елемент 1.
15.10.2011

2

Искате ли елементи от и v1 и v2, които са уникални и не са в другата последователност? Това ми звучи като std::set_symmetric_difference.

Копира елементите от диапазона [first1,last1), които не присъстват в диапазона [first2, last2), и елементите от диапазона [first2,last2), които не присъстват в диапазона [first1, last1) в диапазона започвайки от резултата. Елементите в конструирания диапазон се сортират.

14.10.2011
Нови материали

10 умопомрачителни C# хакове
Здравейте! Като страстен разработчик на C#, аз винаги съм търсил начини да подобря уменията си за кодиране. Вълнувам се да споделя с вас някои умопомрачителни хакове и прозрения, които ми..

Electron с база данни Sqlite3
Electron е рамка за изграждане на междуплатформени настолни приложения с HTML, CSS JavaScript. Electron е написан на C++, Javascript, Objective C, Python и т.н. Днес Electron е супер готин и..

Системи за препоръчване в машинното обучение
Какво представляват двигателите за препоръки? Това е най-мощното и полезно приложение на технологията за машинно обучение в бизнеса. Тези дни. Днес всеки голям гигант като Google, Amazon,..

Топ 5 Python IDE / текстови редактори
Какви IDE на Python трябва да гледам? 1. Pycharm Традиционният пълноценен редактор за Python от JetBrains. PyCharm предоставя широк набор от основни инструменти, тясно интегрирани за..

Извличане на данни от API — част 2
Научете как можете да филтрирате филми въз основа на различни категории. Моля, вижте предишния урок (Част 1) : Как да извличам данни от истински API — React / JS..

Как да предотвратите влизането на някой от вашата кодова база
// TLDR TypeScript добавя статично въвеждане към JavaScript, улавяйки грешки като препращане към променливи извън обхвата или извикване на функции с грешни аргументи. Той е несъвършен и има..

Анализ на настроението с помощта на логистична регресия и наивен Бейс
Нека сравним кой алгоритъм е по-добър за класифициране на туитовете въз основа на техните чувства. Наблюдаван ML При контролираното машинно обучение обикновено имате вход X, който влиза във..