我有两个列表,L 1 和L 2 ,包含抽象数据类型的多个元素(每个唯一元素)(即:structs
)。两个列表中的每一个:
std::vector<myStruct>
容器。我通常期望的是,周期性地,将新元素添加到L 2 ,或者从中减去/删除元素。我试图尽可能有效地检测两个列表中的差异(即:使用最少的比较):
Handle_Missing_Element()
。Handle_New_Element()
。执行上述检查后,L 1 设定为等于L 2 ,并且在将来的某个时间,L 2 < / sub>再次被检查。
我怎样才能找出两个清单之间的差异?我能想到两种方法:
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
vector::push_back()
自动插入元素以使插入预先对列表进行排序,那么这样做是合理的。有没有一种直接的方法可以在C ++中有效地实现这一目标?我发现了类似的问题,但是I need to do more than just find the intersection of two sets,或只用一组整数进行这样的测试,其中可以使用与sum相关的技巧,因为我需要对“new”vs“执行不同的操作”缺少“元素。
谢谢。
答案 0 :(得分:3)
您可以为列表项创建哈希值吗?如果是这样,只需计算哈希并检查哈希表中的其他列表。这很快,不需要排序,并防止您的“每个可能的组合”问题。如果您使用的是C ++和STL,则可以使用map
容器来保存每个列表。
map
将其与您的列表项关联起来。map.find()
)。如果没有,则执行Handle_New_Element()
功能。 Handle_Missing_Element()
函数。 答案 1 :(得分:3)
在插入时自动排序的容器是std::set
。插入将是O(log n),并且比较两组将是O(n)。由于您的所有元素都是唯一的,因此您不需要std::multiset
。
答案 2 :(得分:2)
对于两个数组的每个元素,保持在相反数组中满足它的次数。您可以将这些数字存储在具有相同索引的单独数组中,也可以存储在您使用的结构中。
当 x 元素插入 L2 时,您必须检查它是否与 L1 的所有元素相等。在每次与 y 相等时,增加 x 和 y 元素的计数器。
当从 L2 中删除元素 x 时,您必须再次将其与 L1 的所有元素进行比较。在与 y 的 y 的每次相等时,减去 y 的计数器。 x 的计数器无关紧要,因为它已被删除。
如果要查找非重复元素,可以简单地遍历两个数组。具有零计数器的元素是您需要的元素。
总的来说,每次插入和删除都需要 O(| L1 |)附加操作,每次重复搜索需要 O(| L1 | + | L2 |)操作。如果你额外维护所有元素的列表都是零计数器,后者可以减少到所寻求的非重复元素的数量。
编辑:哎呀,由于每个列表的唯一性,似乎每个计数器总是0或1。
EDIT2:正如Thane Plummer所写,您还可以使用哈希表。如果为 L1 创建哈希表,则可以在 O(1)中插入和删除所有比较。顺便说一下,因为你的 L1 是不变的,所以你甚至可以为它创建a perfect hash table来加快速度。
答案 3 :(得分:2)
之后手动对底层矢量进行排序是不切实际的 每个添加/删除列表。这样做才合理 如果以某种方式可以迫使
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++ );