这是一个CS人员用理论发光的练习。
想象一下,你有两个带元素的容器。文件夹,URL,文件,字符串,这没关系。
什么是计算添加和删除的AN算法?
注意:如果有很多方法可以解决此问题,请为每个答案发布一个,以便对其进行分析和投票。
编辑:所有答案都解决了4个容器的问题。是否可以只使用最初的2?
答案 0 :(得分:4)
假设您有两个独特项目列表,并且排序无关紧要,您可以将它们视为集合而不是列表
如果你想到一个维恩图,列表A作为一个圆圈而列表B作为另一个,那么这两个的交点就是常数池。
从A和B中移除此交叉点中的所有元素,并且A中剩余的任何内容都已删除,而B中剩余的任何内容都已添加。
所以,迭代A搜索B中的每个项目。如果找到它,将其从A和B中删除
然后A是已删除的事物列表,B是已添加的事物列表
我想......
[edit]好的,使用新的“仅限2个容器”限制,同样仍然有效:
foreach( A ) {
if( eleA NOT IN B ) {
DELETED
}
}
foreach( B ) {
if( eleB NOT IN A ) {
ADDED
}
}
然后你没有构建一个新的列表,或者破坏你的旧列表......但是它会花费更长的时间,就像前面的例子一样,你可以循环遍历较短的列表并从较长的列表中删除元素。在这里你需要做两个列表
我认为我的第一个解决方案没有使用4个容器,只是销毁了两个; - )
答案 1 :(得分:1)
我有一段时间没有这样做,但我相信算法是这样的......
sort left-list and right-list
adds = {}
deletes = {}
get first right-item from right-list
get first left-item from left-list
while (either list has items)
if left-item < right-item or right-list is empty
add left-item to deletes
get new left-item from left-list
else if left-item > right-item or left-list is empty
add right-item to adds
get new right-item from right-list
else
get new right-item from right-list
get new left-item from left-list
关于右侧列表与左侧列表的关系,删除包含已删除的项目,添加现在包含新项目。
答案 2 :(得分:0)
乔说。并且,如果列表太大而无法放入内存,请使用外部文件排序实用程序或合并排序。
答案 3 :(得分:0)
缺少信息:如何定义添加/删除?例如。如果列表(A和B)在服务器A和服务器B上显示相同的目录,则表示同步。如果我现在等待10天,再次生成列表并进行比较,如何判断是否已删除某些内容?我不能。我只能说服务器A上的文件在服务器B上找不到和/或反过来。是否因为文件已添加到服务器A(因此在B上找不到该文件)或文件已在服务器B上删除(因此该文件在B 上找不到)是我只能通过列出文件名来确定一些东西。
对于我建议的解决方案,我假设您有一个名为OLD的列表和一个名为NEW的列表。在旧的但未在NEW上找到的所有内容都已删除。已添加在NEW上但未在OLD上找到的所有内容(例如,同一服务器上的同一目录的内容,但是已在不同日期创建列表)。
此外,我将假设没有重复。这意味着任何列表中的每个项目在以下意义上都是唯一的:如果我将此项目与列表中的任何其他项目进行比较(无论此比较如何工作),我总是可以说该项目是更小或更大比我正在比较的那个,但从不相等。例如。在处理字符串时,我可以按字典顺序对它们进行比较,并且列表中的相同字符串永远不会两次。
在这种情况下,最简单的(不一定是最佳解决方案)是:
对OLD列表进行排序。例如。如果列表由字符串组成,则按字母顺序排序。排序是必要的,因为这意味着我可以使用二进制搜索来快速查找列表中的对象,假设它确实存在(或者要快速确定,它根本不存在于列表中)。如果列表未排序,则查找对象的复杂度为O(n)(我需要查看列表中的每个项目)。如果对列表进行排序,则复杂度仅为O(log n),因为在每次尝试匹配列表中的项目之后,我总是可以排除列表中50%的项目不匹配。即使列表有100个项目,找到一个项目(或检测到该项目不在列表中)最多需要7个测试(或者它是8个?无论如何,远远少于100个)。 新列表无需排序。
现在我们执行列表删除。对于新列表中的每个项目,尝试在OLD列表中找到此项目(使用二进制搜索)。如果找到该项目,请从旧列表中删除此项目,然后 将其从新列表中删除。这也意味着消除过程中列表越小越好,因此查找将变得越来越快。由于从列表中删除项目对列表的正确排序顺序没有影响,因此无需在淘汰阶段使用OLD列表。
在淘汰结束时,两个列表可能都是空的,在这种情况下它们是相等的。如果它们不为空,则OLD列表中的所有项目都是新列表中缺少的项目(否则我们已将其删除),因此这些是已删除的项目。仍在新列表中的所有项目都是不在OLD列表中的项目(否则,我们已将其删除),因此这些是添加的项目。
答案 4 :(得分:0)
列表中的对象是“唯一的”吗?在这种情况下,我首先构建两个映射(散列图),然后扫描列表并查找映射中的每个对象。
map1
map2
removedElements
addedElements
list1.each |item|
{
map1.add(item)
}
list2.each |item|
{
map2.add(item)
}
list1.each |item|
{
removedElements.add(item) unless map2.contains?(item)
}
list2.each |item|
{
addedElements.add(item) unless map1.contains?(item)
}
对于混合Ruby和Java的可怕的元语言抱歉:-P
最后 removedElements 将包含属于list1的元素,但不包含list2, addedElements 将包含属于list2的元素。
整个操作的成本是O(4 * N),因为地图/字典中的查找可以被认为是恒定的。另一方面,线性/二进制搜索列表中的每个元素将使O(N ^ 2)。
编辑:第二个想法是将最后一个检查移到第二个循环中,你可以删除其中一个循环...但那很丑......:)
list1.each |item|
{
map1.add(item)
}
list2.each |item|
{
map2.add(item)
addedElements.add(item) unless map1.contains?(item)
}
list1.each |item|
{
removedElements.add(item) unless map2.contains?(item)
}