簡體   English   中英

C / C ++ - 比較兩個列表並找到缺失元素的有效方法

[英]C/C++ - Efficient way to compare two lists and find missing elements

我有兩個列表,L 1和L 2 ,包含多個元素的數據,每個元素都是唯一的抽象數據類型(即: structs )。 兩個列表中的每一個:

  • 可以包含零到一百(包含)元素。
  • 不包含重復元素(每個元素都是唯一的)。
  • 可能包含或不包含其他列表中的元素(即:L 1和L 2可能相同,或包含完全不同的元素)。
  • 沒有排序。
  • 在最低級別,存儲有std::vector<myStruct>容器。

我通常期望的是,周期性地,將新元素添加到L 2 ,或者從中減去/刪除元素。 我試圖盡可能有效地檢測兩個列表中的差異(即:使用最少的比較):

  • 如果L 2中不存在條目並且存在於L 1中 ,則執行一個操作: Handle_Missing_Element()
  • 如果L 2中存在條目而L 1中不存在,則執行另一個操作: Handle_New_Element()

一旦執行上述檢查,L 1被設置為等於L 2 ,並且在將來的某個時間,再次檢查L 2

我怎樣才能找出兩個列表之間的差異? 我能想到兩種方法:

  1. 通過每種可能的元素組合比較兩個列表。 可能是O(n 2 )執行復雜性(可怕)。

bool found;
for i in 1 .. L2->length()
  found = false;
  for j in 1 .. L1->length()
    if (L1[j] == L2[i]
      // Found duplicate entry
      found = true;
    fi
  endfor
endfor
  1. 對列表進行排序,並逐個元素地比較兩個列表,直到找到差異。 這似乎是在接近線性的時間。 問題是我需要對列表進行排序。 在每次添加/刪除列表后手動對底層矢量進行排序是不切實際的。 如果以某種方式可以強制vector::push_back()自動插入元素以使插入預先對列表進行排序,那么這樣做是合理的。

有沒有一種直接的方法可以在C ++中有效地實現這一目標? 我發現了類似的問題,但我需要做的不僅僅是找到兩組的交集 ,或者只用一組整數進行這樣的測試,其中可以使用與sum相關的技巧,因為我需要執行“新”與“缺失”元素的不同操作。

謝謝。

您可以為列表項創建哈希值嗎? 如果是這樣,只需計算哈希並檢查哈希表中的其他列表。 這很快,不需要排序,並防止您的“每個可能的組合”問題。 如果您使用的是C ++和STL,則可以使用map容器來保存每個列表。

  • 為L1中的每個項創建一個哈希,並使用map將其與列表項關聯。
  • 為L2創建一個類似的地圖,並且創建每個L2時檢查它是否在L1地圖中。
  • 將新元素添加到L2時,計算其哈希值並檢查它是否在L1哈希映射中(如果使用STL映射,則使用map.find() )。 如果沒有,則執行Handle_New_Element()函數。
  • 當從L2列表中減去一個元素並且它的散列不在L1散列映射中時,則執行Handle_Missing_Element()函數。

在插入時自動排序的容器是std::set 插入將是O(log n),並且比較兩組將是O(n)。 由於您的所有元素都是唯一的,因此您不需要std::multiset

對於兩個數組的每個元素,保持在相反數組中滿足它的次數。 您可以將這些數字存儲在具有相同索引的單獨數組中,也可以存儲在您使用的結構中。

當元素x插入L2時 ,您必須檢查它是否與L1的所有元素相等。 在與y的每個相等上,增加元素xy的計數器。

當元素xL2中移除時,您必須再次將其與L1的所有元素進行比較。 在與L1的 y的每個相等上,遞減y的計數器。 x的計數器無關緊要,因為它被刪除了。

如果要查找非重復元素,可以簡單地遍歷兩個數組。 具有零計數器的元素是您需要的元素。

總的來說,每次插入和刪除需要O(| L1 |)附加操作,每次重復搜索需要O(| L1 | + | L2 |)操作。 如果您另外維護具有零計數器的所有元素的列表,則后者可以減少到所尋求的非重復元素的數量。

編輯:哎呀,似乎每個計數器總是0或1,因為每個列表的唯一性。

EDIT2:正如Thane Plummer所寫,您還可以使用哈希表。 如果為L1創建哈希表,則可以在插入和刪除O(1)中進行所有比較。 順便說一句,因為你的L1是不變的,你甚至可以為它創建一個完美的哈希表來加快速度。

在每次添加/刪除列表后手動對底層矢量進行排序是不切實際的。 如果以某種方式可以強制vector::push_back()自動插入元素以使插入預先對列表進行排序,那么這樣做是合理的。

你在這里談論的是一個有序插入 <algorithm>中有一些功能允許您執行此操作。 而不是使用std::vector::push_back你將使用std::vector::insert ,並調用std::lower_bound ,它對不小於給定值的第一個元素進行二進制搜索。

auto insert_pos = std::lower_bound( L2.begin(), L2.end(), value );
if( insert_pos == L2.end() || *insert_pos != value )
{
    L2.insert( insert_pos, value );
}

這使得每次插入O(logN),但如果您在定期檢查之間進行的插入次數少於N次,那么它應該是一種改進。

壓縮操作可能如下所示:

auto it1 = L1.begin();
auto it2 = L2.begin();

while( it1 != L1.end() && it2 != L2.end() )
{
    if( *it1 < *it2 ) {
        Handle_Missing( *it1++ );
    } else if( *it2 < *it1 ) {
        Handle_New( *it2++ );
    } else {
        it1++;
        it2++;
    }
}

while( it1 != L1.end() ) Handle_Missing( *it1++ );
while( it2 != L2.end() ) Handle_New( *it2++ );

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM